排他ロック/leaseを排他の正本にするなら、全処理主体が所有権を再確認し、lease寿命を可視性・再配信窓より長く順序づけ、cleanup完了までメッセージを消さない
並行処理
設計判断
キュー設計
非同期処理
信頼性
原則
分散した排他ロック/lease を「同一資源で常に1処理」という排他不変条件の正本にするなら、その所有権の整合性を、取得の一度きりのチェックではなく、全処理主体の所有権再確認・寿命の順序づけ・cleanup 完了までのメッセージ保持という三点で守る。最適化するのは「メッセージ再配信・stale lock 奪取・worker 異常終了があっても排他不変条件が破れないこと」、避けるのは「ジョブ作成時の一度きりの排他チェックだけで同時実行しないと判断すること」と「処理主体ごとに別々の正本(片方はロック、片方は処理中ステータス)を見る非対称設計」。
判断基準
- ロック/lease を排他の正本にするなら、全処理主体(作成側・実行 worker・再配信された古いメッセージ)が同じ正本を見る。worker は処理開始時と、副作用のまとまり(chunk 境界)ごとに、その正本が自分の所有(自分の job / owner を指す)であることを条件付き更新の影響行数などで再確認し、失っていたら後続を止める。再配信や stale 復旧を異常でなく正常系として扱い、所有権を持たない経路は処理本体へ進ませない。
- lease の寿命(stale 閾値)と、メッセージ可視性タイムアウトや意図的な待機保持の窓を、各定数を別々に決めず『stale 閾値 が 再配信/待機窓 より長い』という大小関係そのものを不変条件として順序づける。長時間処理では処理中に heartbeat とメッセージ可視性の双方を延長する。アプリ側 heartbeat は元 worker の生存を示すだけでブローカーの再配信カウントは止めないため、両方を延ばす。
- 終端状態(完了/失敗)になっても、ロック解放・lease 返却・外部リソース解放などの cleanup が別操作で未完了なら、メッセージを入口で即削除しない。cleanup recovery の入口として実行主体へ渡し、cleanup 成功後にだけ削除する。入口で即削除してよいのは、対象が存在しない・payload が壊れているなど、再配信しても cleanup 不能なメッセージに限る。
適用条件・境界
- 排他ロック/lease と再配信のあるキューワーカー全般に効く。単発の同期処理や、そもそも保持せず毎回取り直す設計には過剰。
- 「失敗後どう整合へ戻すか」(外部副作用のコミット後・冪等化、資源の能動解放、一時/恒久障害の分類)は別の姿勢として扱い、本項には混ぜない。ここは所有権正本の整合性そのものに閉じる。
検証
逐次の単体検証では競合窓が再現しないため、stale 閾値と待機/可視性タイムアウトの大小関係自体をテストで固定する。stale 奪取と古いメッセージ再配信を並行で起こし、所有権を失った側が処理本体に入らず停止すること、cleanup を意図的に失敗させたときにメッセージが削除されず再配信で再試行できることを、mock でなく実機構で確認する。
根拠(synthesize 元)
- 594 共有排他ロックは取得側だけでなく処理側も所有権を再確認する
- 591 stale-lock 奪取復旧と『リトライ待機中のロック保持』は競合する — 保持中はリースを延命するか奪取閾値を待機窓より長くする
- 588 長時間キューワーカーはロック heartbeat だけでなくメッセージ visibility も延長する
- 589 終端状態のキューメッセージも cleanup が未完了なら worker へ渡す