複数のタブが同じoriginの保存領域を更新したり、同じバックグラウンド処理を始めたりすると、重複や競合状態が発生することがあります。Web Locks APIは同じoriginのブラウザー内スクリプトが名前付きロックを要求し、処理を調整できるようにします。共有範囲はブラウザー内であり、サーバーや別端末まで共有する分散ロックではありません。 対応ブラウザーのHTTPSなどのsecure contextで利用できるAPIです。

同じoriginのタブAがcallbackのPromise完了までexclusiveロックを保持し、解放後に待機中のタブBが取得する流れ

1. 名前とshared・exclusiveモード

navigator.locks.request(name, callback)にロック名と処理関数を渡します。既定の要求はexclusiveで、同じ名前の別のexclusive要求が同時にクリティカルセクションへ入らないよう調整します。読み取りのように同時実行できる処理ではmode: 'shared'を要求できます。複数のsharedロックは同時に保持でき、同じ名前のexclusive要求はshared保持者が終了するまで待ちます。

ロック名はアプリケーションが決める論理識別子です。保存データ同期とレポート生成が同じ資源を変更するなら共通の名前を使う必要があります。無関係な資源に同じ名前を使うと不要な待機が生まれ、同じ資源に別名を使うと調整できません。資源へアクセスするコード全体で命名規則を揃えます。

2. CallbackのPromiseが決めるロック期間

要求が許可されるとブラウザーはcallbackを呼び出します。ロックはcallbackが返すPromiseが成功または失敗で終了するまで保持されます。保護が必要な非同期処理はcallback内で待機してください。処理を始めるだけで完了前にcallbackを返すと、ロック解除後に処理が続くことがあります。逆に長いネットワーク要求やユーザー入力をロック内で待つと、他のタブを長く待たせます。

3. 同じoriginの範囲と調整の限界

Web Locksは同じoriginのブラウザーコンテキスト間で資源利用を調整します。別origin、別ブラウザープロファイル、別端末のプロセスとはロックを共有しません。タブが閉じたりworkerが終了したりすると実行コンテキストも終わることがあるため、ロックを永続タスクキューとして扱ってはいけません。重要な結果は別途ストレージやサーバーに記録します。

このAPIは競合を減らす手段であり、データベーストランザクションやサーバー側の冪等性キーではありません。複数のロックを入れ子で取ると取得順により互いを待つ可能性があります。資源名を必要な範囲に絞り、callbackを短くし、タブやブラウザーが終了しても状態を復旧できるようにします。保持中のアクセス調整は行いますが、すべての処理を原子的・永続的にはしません。

4. 専門的視点:即時に見送るか待機を取り消すか

MDNのrequest()専門リファレンスでは、ifAvailableがtrueで直ちに取得できない場合、callbackにはLockではなくnullが渡されると説明します。callbackの呼び出しだけで保護区間へ入ったと判断してはいけません。nullの分岐では保護が必要な更新を実行せず、その回の処理を見送るなどの方針を選べます。キャッシュ再生成がすでに進んでいる場合、別タブが重複した再生成を始めない使い方です。

signalに渡すAbortSignalは、まだ許可されていない要求の待機を取り消します。MDNは取り消された要求のPromiseが拒否されると説明します。このオプションは、すでに実行中のcallbackの業務処理を自動的に中止しません。進行中のfetchなどを止めたい場合は、その操作自身のキャンセル機構へ別途信号を接続し、一部だけ完了した状態も扱う必要があります。

二つは異なる方針です。ifAvailableは取得できなければnullの分岐へ進み、signalは待機中の要求を取り消します。MDNはsignalを指定してifAvailableをtrueにするとNotSupportedErrorになると記載するため、一つの要求へ併用しません。ロックを保持するタブを用意し、nullの分岐、待機中の取り消し、callback開始後の信号を別々に試すと、取得待ちと実際の処理の境界を確認できます。

参考資料