非同期処理とジョブキュー設計の勘所|リトライ・冪等性・デッドレターキュー

メール送信や帳票生成をリクエスト処理の中で同期的に実行していて、外部サービスの遅延に引きずられてAPI全体がタイムアウトする——非同期化を検討するきっかけは、たいていこうした障害です。しかし場当たり的にキューを導入すると、今度は「ジョブが消えた」「二重に実行された」という別の問題に悩まされます。

この記事では、非同期処理を設計するときに最初から決めておくべき4つのポイント——切り出しの判断基準、リトライ設計、冪等性、デッドレターキュー——を整理します。

目次

同期処理から切り出す判断基準

何でも非同期にすればよいわけではありません。非同期化はエラー通知やデバッグを難しくするコストを伴うため、次の条件に当てはまるものから切り出します。

  • レスポンスに結果が不要: メール送信、通知、ログ集計など「受け付けた」ことだけ返せばよい処理
  • 外部サービスに依存する: 相手の遅延・障害を自システムのレスポンスから切り離したい処理
  • 処理時間が長い・変動する: 帳票生成、画像変換、大量データの一括更新
  • 失敗してもリトライで回復できる: 後述する冪等性を担保できる処理

逆に、ユーザーがその場で結果を必要とする処理(決済の成否確認など)を安易に非同期化すると、ポーリングや通知の仕組みが別途必要になり、かえって複雑化します。

リトライは「間隔」と「上限」をセットで設計する

非同期ジョブの失敗は前提です。問題は失敗したときの振る舞いを決めていないことで、固定間隔で無限リトライする実装は、障害中の外部サービスへ負荷をかけ続けて復旧を妨げます。

  • 指数バックオフ: 1分→2分→4分…と間隔を広げる。ジッター(ランダムなゆらぎ)を加えて再試行の同時集中を避ける
  • リトライ上限: 5回前後を目安に設定し、超えたらデッドレターキューへ
  • リトライすべきでないエラーの区別: バリデーションエラーなど再実行しても成功しないものは即座に失敗扱いにする

「一時的エラー(ネットワーク断、429/503)はリトライ、恒久的エラー(400系の入力不正)はリトライしない」という分類をワーカー実装の規約として決めておくのが実務のポイントです。

冪等性の担保——「少なくとも1回」を前提に書く

多くのキュー(Amazon SQSなど)の配信保証は「at least once(少なくとも1回)」です。つまり同じジョブが2回配信されることは正常系として扱う必要があります。二重実行でメールが2通届く、ポイントが二重加算される、といった事故はここを見落とすと起きます。

基本パターンは、ジョブに一意なIDを持たせ、処理済みIDを記録してから実行することです。

// 擬似コード: 処理済み記録のユニーク制約で二重実行を防ぐ
void handle(Job job) {
    try {
        insertProcessedRecord(job.getId()); // UNIQUE制約あり
    } catch (DuplicateKeyException e) {
        return; // すでに処理済み → 何もせず正常終了
    }
    doWork(job);
}

UPDATE系の処理なら「絶対値をセットする」(加算ではなく結果の値を書く)形に寄せるだけでも、二重実行の影響を抑えられます。

デッドレターキューは「作って終わり」にしない

リトライ上限を超えたジョブの行き先がデッドレターキュー(DLQ)です。DLQがないと失敗ジョブは黙って消え、「処理されたはずのデータがない」という調査困難な問い合わせになって返ってきます。

ただしDLQは作るだけでは機能しません。運用として次の3点をセットで用意します。

  • DLQにメッセージが入ったらアラートを飛ばす(滞留数の監視)
  • 原因調査に必要な情報(元のペイロード、失敗理由、試行回数)が残るようにする
  • 修正後にDLQから元のキューへ再投入する手順をあらかじめ整備しておく

まとめ

非同期処理の設計は、キュー製品の選定よりも「失敗をどう扱うか」の決め事が本体です。結果を待たなくてよい処理から切り出し、指数バックオフと上限つきのリトライを設定し、二重配信を前提に冪等な実装にして、行き場を失ったジョブはDLQで監視する。この4点を最初に設計書へ明文化しておけば、非同期化にありがちな「消えるジョブ」「二重実行」の障害を大きく減らせます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

クラウド・バックエンドエンジニア。AWSを中心に設計・構築から運用までを担当しています。主要言語は Java・JavaScript・Python。運用の現場で拾った知見を、再現できる手順に落として残すのがこのブログのテーマです。

目次