Article

📨 SQSのVisibility Timeoutを理解する:二重処理を前提に安全なワーカーを作る

aws, sqs, backend, java

Amazon SQSでワーカーを作るときに重要なのがVisibility Timeoutです。

Visibility Timeoutは、メッセージを受信したワーカーが処理している間、そのメッセージを他のワーカーから一時的に見えなくする時間です。

基本の流れ

  1. ワーカーがメッセージを受信する
  2. メッセージがVisibility Timeoutの間見えなくなる
  3. 処理に成功したらDeleteMessageで削除する
  4. 削除されないままTimeoutを超えると再び受信可能になる

つまり「受信したら消える」のではなく、正常終了後に明示的に削除する仕組みです。

処理時間より短いTimeoutは危険

処理に60秒かかるのにVisibility Timeoutが30秒だと、最初のワーカーがまだ処理中でもメッセージが再表示されます。

その結果、別ワーカーも同じメッセージを処理し、二重実行が発生する可能性があります。

長すぎても困る

逆に30秒で失敗を検知できる処理なのにVisibility Timeoutを30分にすると、失敗したメッセージの再試行まで長時間待つことになります。

処理時間の実測値を基準に、十分な余裕を持たせつつ長くしすぎない値にします。

長時間処理では延長する

処理時間が一定でない場合はChangeMessageVisibilityで途中からVisibility Timeoutを延長できます。

JavaのAWS SDKでは、処理中に定期的に延長する構成も可能です。

ただし無限に延長するのではなく、最大処理時間を決め、異常な処理は失敗として扱う方が運用しやすくなります。

二重処理は完全には避けられない

SQS Standard Queueは少なくとも1回配送される設計です。そのためVisibility Timeoutを適切に設定しても、同じメッセージが複数回届く可能性をゼロにはできません。

そこでワーカー側を冪等にします。

冪等とは「同じ処理を複数回実行しても結果が壊れない性質」です。

例えば注文IDをDBに記録し、処理済みなら再実行しない方法があります。

DLQも組み合わせる

何度処理しても失敗するメッセージはDLQ(Dead Letter Queue)へ送ると調査しやすくなります。

Visibility Timeout、再試行回数、DLQをセットで設計すると、失敗時の挙動が明確になります。

まとめ

SQSでは「一度受信したから一度しか処理されない」と考えないことが重要です。

  • Visibility Timeoutは処理時間より十分長くする
  • 長時間処理では必要に応じて延長する
  • 二重配送を前提に冪等化する
  • 繰り返し失敗する処理はDLQへ送る

参考