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