排他ロックを持つキューワーカーはリトライ枯渇時にロックを能動解放する(配信回数を見る)
バックエンド
設計判断
キュー設計
非同期処理
判断
運用
キューワーカーが「per-tenant / per-resource の排他ロック(長めの TTL)を取り、失敗時はメッセージの再配信に retry を委ねる」設計には、リトライ枯渇時にロックが残置する落とし穴がある。リトライ上限(DLQ 退避条件)に達したメッセージは元のワーカーに二度と配信されないため、ジョブが「処理中」状態のまま放置され、ロックも TTL(例: 数時間)まで残り、リソース(テナント等)が新規ジョブを開始できなくなる。「次の起動時に期限切れなら解放」だけの仕組みだと、その TTL ぶんブロックが続く。
対処(判断基準)
- ブローカーが持つ配信回数(SQS の ApproximateReceiveCount 等)をワーカーに渡し、「次に失敗したら DLQ 行き」の最終配信で失敗したときは、放置せずジョブを失敗確定(FAILED)+ロック解放する。メッセージ自体は削除せず DLQ へ流せば原因調査用に残せる。これでブロック時間が「ロック TTL」から「再配信1サイクル」に縮む。
- 配信回数の上限はブローカー側(redrive policy 等)が正本なので、ワーカーには env / 設定で同じ値を渡し、ハードコードでドリフトさせない。
- 可視性タイムアウト超過で並行再配信が起きる環境では配信回数が意図せず増えうる。窓を小さく保つ(コミットを速く)か、heartbeat / 可視性延長を別途検討する。
transient / permanent 分類の非対称性(関連)
「一時障害か恒久障害か」を分類して retry 要否を決めるとき、データ更新ジョブでは false-permanent(一時障害を恒久と誤判定)の方が false-transient より実害が大きいことが多い。false-permanent はそのバッチ/チャンクを「失敗」として黙ってスキップし更新が入らない。false-transient は無駄な retry を1回するだけ(上限と上記の自己終端があれば有界)。よって分類は「疑わしきは transient(retry 寄り)」にし、明確に恒久と分かる例外だけ permanent に倒すのが安全。allowlist で transient を厳密列挙すると取りこぼしが false-permanent になりやすい。
検証
最終配信に相当する配信回数で失敗を起こし、(1) ジョブが FAILED になる、(2) ロックが即解放される、(3) メッセージは DLQ に残る、(4) 同リソースの新規ジョブが TTL を待たず開始できる、ことを確認する。