Article
📨 SQSのVisibility Timeoutを理解する:二重処理を前提に安全なワーカーを作る
Amazon SQSでワーカーを作るときに重要なのがVisibility Timeoutです。
Visibility Timeoutは、メッセージを受信したワーカーが処理している間、そのメッセージを他のワーカーから一時的に見えなくする時間です。
基本の流れ
- ワーカーがメッセージを受信する
- メッセージがVisibility Timeoutの間見えなくなる
- 処理に成功したらDeleteMessageで削除する
- 削除されないまま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へ送る
参考
- Amazon SQS visibility timeout
- Amazon SQS delivery guarantees