クライアントC1とC2によって使用されるデータベースに共有リソースがあります。リソースがC1によって読み取られる前に、C1はリソースをリース済みとしてマークし、C2がリソースがビジーであることを認識できるようにする必要があります。 C1はいくつかの作業を行い、完了するとリースを更新してリソースをC2で使用できるようにします。私はリースを使用しているので、Cxのホストシステムがクラッシュした場合、別のCが時間Tの後にリソースを使用できるようになります。
フローは次のようになります。
データベーストランザクションの開始
C1はリソースを読み取り、リース時間をチェックしてcurrent time >= leasetime + T
を確認します。
C1は、現在の時刻のタイムスタンプをリース列に書き込みます
データベーストランザクションの終了
C1がリソースの使用を開始します
C2はリソースを読み取り、リース時間をチェックしますが、current time < leasetime + T
であるため、リソースはビジーです
C2はエラーを返します
C1が終了し、リースにcurrent time - T
を書き込みます
C2は再試行し(ステップ1-3)、リソースをリースできるようになります
C1とC2は通信できません。
私の素朴な実装は、リソースにホストシステムからのタイムスタンプをタグ付けして、リースとしてマークすることです。 C2がリソースを読み取ろうとすると、タイムスタンプが時間T以内であり、リソースがビジーであることを意味します。その後、C2はユーザーにエラーを返し、再試行するように求めます。このソリューションは、C1とC2のホストシステムのシステム時間に依存し、その時間が異なる場合があるため、機能しません。
私が考えていたのは、データベースの時間を使用して、リソースがリースされているか、自由に使用できるかを計算することでした。しかし、時間に依存することはまだ悪い解決策のように思えます。
C1が終了するまでCnがリソースを使用しないようにするには、どうすればよいですか?
dbトランザクションを開始します(必ず 明示的なロック を使用してください!)
C1はリソースを読み取り、_is_busy = false
_をチェックします
C1は_is_busy = true
_と_leased_at
_を現在のタイムスタンプで書き込みます
データベーストランザクションの終了
C1がリソースの使用を開始します
C2はリソースを読み取り、_is_busy
_がtrueであることを確認します
C2はエラーを返します
C1が終了し、_is_busy = false
_を書き込みます
C2は再試行し(ステップ1-3)、リソースをリースできるようになります
データベーストランザクションを開始します
C1はリソースを読み取り、_is_busy = false
_をチェックします
C1は_is_busy = true
_と_leased_at
_を現在のタイムスタンプで書き込みます
データベーストランザクションの終了
C1クラッシュ
C2はリソースを読み取り、_is_busy
_がtrueであることを確認します
C2はエラーを返します
いくつかの個別のスレッド/プロセス/サービス/データベース自体( pgAgent のようなsmth)は、_is_busy
_の値をチェックすることにより、_leased_at
_が長時間ロックされているかどうかを監視します。クエリはupdate table set is_busy = false where is_busy = true and leased_at < now() - interval '15 minutes'
のようになります
C2は再試行し(ステップ1-3)、15分でリソースをリースできます