「やり直し」に強いシステム

操作ミスやエラーからの復旧を容易にする、重複防止と自動リトライの設計

重複防止リトライべき等性エラー回復指数バックオフ
読了時間: 8分

このトピックについて

業務システムで最も困るのは、操作ミスやエラーからの復旧です。「同じ請求書が2枚できてしまった」「途中でエラーになったけど、どこまで処理されたかわからない」といった問題は、現場を混乱させます。

このプロジェクトでは、さまざまな「うっかり」に対応できる設計にしました。

同じ請求書を2回送っても大丈夫

「べき等性(Idempotency)」という仕組みで、重複処理を防止しています。

重複防止の仕組み
1回目のリクエスト

key="invoice:001" で送信

キャッシュ確認

未登録 → 新規処理として実行

結果を保存

key="invoice:001" → 成功、ID: 12345

2回目のリクエスト(同じキー)
2回目のリクエスト

key="invoice:001" で再送信

キャッシュ確認

登録済み → 前回の結果を確認

前回の結果を返却

処理スキップ、ID: 12345を返却

べき等性キーの設計

各リクエストには一意のキーを付与します。同じキーで2回目の送信があった場合は「すでに作成済み」として処理をスキップします。

comp1:invoice:001
構成会社ID + 伝票種類 + 伝票番号
用途請求書の重複防止
comp1:delivery:2024-001
構成会社ID + 伝票種類 + 伝票番号
用途納品書の重複防止

7日間の記憶

結果は7日間キャッシュに保持されます。1週間以内であれば、「この請求書は作成済みかどうか」を確認できます。

通信エラー時の自動リトライ

ネットワークの一時的な不調や、サーバーの混雑時には、自動的に少し待ってから再試行します。

指数バックオフとジッター

「指数バックオフ」は、リトライの間隔を徐々に長くする手法です。「ジッター」は、ランダムな遅延を加えることで、複数のクライアントが同時にリトライして再び混雑することを防ぎます。

リトライの流れ
リクエスト送信

API呼び出しを実行

エラー発生

429(レート制限)または5xx(サーバーエラー)

1回目リトライ

300ms + ランダム(0〜199ms)待機

2回目リトライ

600ms + ランダム待機

3回目リトライ

1200ms + ランダム待機

最大5回まで

上限に達したらエラーを返却

リトライ可能なエラー

すべてのエラーでリトライするわけではありません。一時的なエラーのみリトライします。

429
意味リクエストが多すぎる(レート制限)
リトライする
500〜599
意味サーバー側の一時的エラー
リトライする
400
意味リクエストが不正
リトライしない(修正が必要)
401
意味認証エラー
リトライしない(トークンを確認)
404
意味リソースが見つからない
リトライしない

詳細なログで問題を特定

いつ・誰が・何を実行して・どうなったかを記録します。エラーが発生した場合も、どの行でどんな問題が起きたかが明確にわかります。

構造化ログの例

{
  "event": "row_processed_error",
  "docType": "invoice",
  "rowNumber": 5,
  "idempotencyKey": "comp1:invoice:001",
  "httpStatus": 422,
  "error": "partner_code not found",
  "timestamp": "2025-01-24T10:30:00.000Z"
}

ログから読み取れること

event
内容何が起きたか
用途イベントの種類を特定
rowNumber
内容何行目で発生したか
用途スプレッドシートの該当行を確認
httpStatus
内容APIの応答コード
用途エラーの種類を把握
error
内容エラーメッセージ
用途具体的な原因を特定
timestamp
内容発生時刻
用途時系列での追跡

エラー発生時のフロー

エラー対応の流れ
エラー発生

スプレッドシートのステータス列に「エラー」表示

原因確認

ログからエラー内容を確認。rowNumberで該当行を特定

データ修正

スプレッドシートで問題のあるデータを修正

再実行

修正した行を選択して再送信。べき等性キーが変わるため新規処理として実行

この設計で実現できること

運営側にとって

  • 重複請求の防止: 同じ請求書が2枚作成されることはない
  • 一時的障害への耐性: 自動リトライで回復
  • 原因特定の容易さ: 構造化ログで問題箇所を即座に把握

現場担当者にとって

  • 安心して操作できる: ミスしても大丈夫という安心感
  • すぐに状況がわかる: ステータス表示で結果を確認
  • 簡単に再実行できる: 修正して再送信するだけ

関連するトピック

関連記事