プロンプトとスコープ
共同編集ファイルサービスは WebDAV をサポートしており、クライアントが同一リソースを編集できるようにしています。書き込み、移動、または削除の処理時に 423 Locked が返されることがあります。423、409、403 の境界、クライアントがロックトークンを取得および送信する方法、depth、timeout、更新(renewal)、オーナーのクラッシュを処理する方法、そして復旧プロセスを可観測にする方法について説明してください。
面接官がテストしているポイント
- 423 を単なる一般的な並行性エラーではなく、対象リソースをブロックしているロックとして説明できるか。
- Lock-Token、If、Timeout、UNLOCK を連携して理解しているか。
- 恒久的なロックや誤ったアンロックを起こすことなく、リース、再接続時の復旧、認可を設計できるか。
- クライアントが「待機」、「再取得」、「再試行不可能な失敗」を適切に区別できるか。
最初に確認すべき質問
- このロックは WebDAV の書き込みロックですか、アプリケーション層の編集リースですか、あるいはその両方ですか?
- 単一のリソースを対象としていますか、それとも無制限深度(infinity-depth)のコレクションを対象としていますか?また、子リソースはどのように継承または除外されますか?
- トークンはどこに保存され、テナント、プリンシパル、リソースバージョン、権限に紐付けられていますか?
- 切断、プロセスクラッシュ、クロックスキューの発生時、誰がリースを更新し、回収しますか?
- プロキシが書き込みを再試行することは可能ですか?また、クライアントは安全にリクエストボディを再送できますか?
30秒での回答
423 は、現在ロックが存在するために対象リソースへメソッドを適用できないことを意味し、一般的な権限拒否やあらゆるバージョン競合を指すものではありません。私ならスコープ、オーナー、残存リース期間を確立し、If 条件内で一致する Lock-Token の提示を要求します。サービスがリースを管理し、モノトニック(単調増加)時間を使用します。更新は認可され制限された期間で行われ、クラッシュ後は有効期限切れによってロックが回収されます。クライアントは 423 を計画的な待機や再取得として扱い、非冪等な書き込みリクエストを盲目的に再送することはありません。
ステップバイステップの詳細解説
ステップ 1: プロトコル境界を定義する
RFC 4918 では、ロックされたリソースにメソッドを適用できない場合に 423 を使用します。403 は認可に関するものであり、409 は現在の状態との競合に関するものであるため、ステータスを選択する前にブロックの原因を分類します。
ステップ 2: ロックの識別子とスコープを定義する
リソース識別子、ロックルート、深度(depth)、オーナー、トークン、作成時刻、リース、パーミッションドメイン、リソースバージョンを保存します。infinity-depth のロックは子リソースをカバーできるため、サーバーは単に URL を確認するだけでなく、書き込みごとに継承関係を解決します。
ステップ 3: Lock-Token を検証する
クライアントは LOCK メソッドでトークンを取得し、その後の書き込み、移動、削除リクエストの If 条件にトークンを付与して送信します。サーバーはトークン、スコープ、プリンシパル、テナントを検証します。トークンの欠落、不正な形式、他者のトークンに対しては、別テナントのオーナー情報を開示することなく、診断可能なエラーを返します。
ステップ 4: タイムアウトと更新にリースを使用する
Timeout はクライアントからの要求値であり、無制限のリースを作成する権限ではありません。サーバーはモノトニッククロックを使用して有効期限を保存し、更新要求を認証し、最大期間に上限を設けます。レスポンスで付与されたタイムアウト値を通知し、クライアントはその値に基づいて更新をスケジュールします。クラッシュ発生時は有効期限切れによってロックが回収されます。
ステップ 5: 切断と復旧を処理する
再接続後、オーナーはロック状態を照会し、有効なトークンが残っている場合にのみ更新します。ローカルキャッシュは所有権を証明できません。再起動時は永続ストレージからリースを復元します。安全な復元が証明できない場合はロックを無効化し、古いトークンで書き込みが行われないよう再取得を要求します。
ステップ 6: 待機と再試行を分離する
クライアントは保持者の詳細を隠蔽した「リソース編集中のため占有」状態を表示し、残存リース期間に基づいてバックオフしながらポーリングできます。423 は一時的なネットワーク障害ではありません。トークン、バージョン、ボディが再送可能であると確認できた場合にのみ書き込みを再試行します。プロキシは実行結果が不明な非冪等リクエストを再試行してはなりません。
ステップ 7: 悪用の監視と抑制
リソースハッシュ、ロックスコープ、残存リース期間、失敗理由、プリンシパルハッシュ、リクエスト ID を記録します。423 の発生率、保持時間、更新失敗、期限切れによる回収、深度ロック数を、テナント、リソースタイプ、クライアントバージョンごとに測定します。リソース枯渇やトークンの推測攻撃を抑止するため、深度ロック数、最大リース期間、トークン試行回数を制限します。
質の高い模範解答
まず 423 が WebDAV のロックであることを明確にし、403 の認可エラーや 409 のアプリケーション状態の競合と区別します。ロックサービスは、リソース、深度、プリンシパル、テナント、Lock-Token、付与されたリース、バージョンを永続化します。クライアントは LOCK でトークンを取得し、If ヘッダーでそれを提示します。サーバーはトークン、スコープ、プリンシパル、パーミッションをまとめて検証します。リース管理にはサーバー側のモノトニック時間を使用し、最大期間を設定します。切断後、クライアントは有効なトークンでのみ更新でき、クラッシュ後は有効期限切れによってロックが回収されます。クライアントは回復可能な「編集中占有」状態を UI に表示してバックオフ付きでポーリングを行い、結果が不確定な書き込みを盲目的に再試行しません。本番環境のテレメトリでは 423 発生率、保持時間、更新失敗、回収数、深度ロック数を監視し、競合するクライアント、再起動、クロックスキュー、プロキシの再試行に対するテストを実施します。
よくある落とし穴
- すべての並行性競合に対して 423 を返し、バージョンエラーや権限エラーを覆い隠してしまう。
- ロックをメモリ上でのみ保持し、クラッシュ後に恒久的なロックが残ったり誤ってアンロックされたりする。
- 付与されたリース期間を返さずに、クライアントからの無制限な Timeout 要求をそのまま受け入れる。
- スコープ、テナント、プリンシパルの権限を検証せず、トークン文字列の比較のみを行う。
- 副作用のある書き込みをプロキシが再試行し、リクエストを二重に適用してしまう。
フォローアップ質問と回答
423 と 409 はどのように使い分けるべきですか?
有効なロックによってメソッドの実行が阻まれている場合は 423 を使用します。ロックは存在しないものの、リクエストが現在のバージョンや状態と競合している場合は 409 を使用します。どちらの場合も、クライアントが問題を診断して復旧できるパスが必要です。
無制限深度(infinity-depth)のロックはどのように制御しますか?
その権限と作成数を制限し、対象リソースへの継承チェーンを解決した上で、移動・コピー・削除時に適用範囲を再計算します。継承を暗黙的に前提とするのではなく、テナント間やコレクション間をまたぐ操作は明示的に拒否します。
クラッシュ後に管理者が強制アンロックすることは可能ですか?
明示的な権限と監査可能な理由がある場合に限り可能です。通常のクライアントは期限切れを待ちます。強制アンロックを行う場合は古いトークンを無効化し、操作者、理由、リソースバージョンを記録します。
サーバー間でクロックスキューが発生した場合はどう対処しますか?
単一ノードまたは合意形成に基づいたデータストアでモノトニック時間を使用して有効期限を管理し、クライアントには付与された残存期間に依存させます。複数ノードにまたがる更新にはバージョン条件を設け、2つのノードが単一のロックを同時に延長できないようにします。