分散ロック
共有リソースへのアクセスをリアルタイムで管理し、希望する順番でデータを処理できるようにする
場合によっては、アプリケーションインスタンス間で共有されるリソースがあり、それぞれが順番にアクセスする必要があります。例えば、値をインクリメントする場合、2つのクライアントが同時に値 1 を読み取ったとすると、それぞれが値を 2 にインクリメントしてしまいます。しかし、本来期待される動作は、値が2回インクリメントされ、最終的に 3 になることです。
このシナリオは、システムが同時に2つ以上の操作を実行しようとする際に発生する race condition (レースコンディション) の例です。しかし、システムの性質上、これらの操作は正しい順序で実行されなければなりません。
Squid は、共有データを適切に同期し、レースコンディションを解決するために使用できる分散ロックを開発者に提供します。
分散ロックの作成
共有リソースへのアクセスを同期するために、ロックを一意に識別する文字列値を mutex パラメータとして渡し、acquireLock メソッドを使用できます:
const distLock = await squid.acquireLock('YOUR_MUTEX_STRING');
このメソッドは、指定された mutex に対する分散ロックを解決する Promise を返します。別のクライアントが既にロックを獲得している場合、ロックが解放されるかサーバーとの接続が失われるまで、Promise の解決は待機されます。
ロックの解放
release() メソッドが呼び出されるか、サーバーとの接続が失われた場合、ロックは解放されます。クライアントが切断された場合も、自動的にロックが解放されます。
// 作業が完了した際にロックを解放する
distLock.release();
これらのメソッドを組み合わせると、ワークフローは次のようになります:
const distLock = await squid.acquireLock('YOUR_MUTEX_STRING', 5000);
try {
// 共有リソースに対するアクションを実行
} catch (e) {
// タイムアウトなどのエラーをキャッチ
} finally {
distLock.release(); // 不要になったらロックを解放
}
ロックが解放されているか確認するには、isReleased() メソッドを使用します。このメソッドは、ロックが解放されていれば true を返すブール値を返します。
console.log(distLock.isReleased()); // true または false
observeRelease() メソッドを使用することで、ロックの解放時にアクションを実行できます。これは、ロックが解放された時にイベントを発行する observable を返します。
distLock.observeRelease().subscribe(() => {
// ロック解放時に何らかの処理を実行
});
コールバックを使用した分散ロックの管理
分散ロックを管理するために、withLock() メソッドを使用することもできます。このメソッドは、指定された mutex のロックを保持した状態で、与えられたコールバックを実行します。コールバックが終了するとロックが解放されるため、withLock() を使用する場合は release() メソッドを呼び出す必要はありません。
squid.withLock('YOUR_MUTEX_STRING', async () => {
// データの読み取りや更新などのタスクを完了
return; // 関数を返すことも可能
});
分散ロックのセキュリティ確保
デフォルトでは、分散ロックは完全に保護されており、Squid のバックエンドセキュリティ機能が許可した場合にのみ呼び出すことができます。詳細については、バックエンドドキュメントの securing distributed locks をご覧ください。