このトピックについて
業務システムで最も困るのは、操作ミスやエラーからの復旧です。「同じ請求書が2枚できてしまった」「途中でエラーになったけど、どこまで処理されたかわからない」といった問題は、現場を混乱させます。
このプロジェクトでは、さまざまな「うっかり」に対応できる設計にしました。
同じ請求書を2回送っても大丈夫
「べき等性(Idempotency)」という仕組みで、重複処理を防止しています。
key="invoice:001" で送信
未登録 → 新規処理として実行
key="invoice:001" → 成功、ID: 12345
key="invoice:001" で再送信
登録済み → 前回の結果を確認
処理スキップ、ID: 12345を返却
べき等性キーの設計
各リクエストには一意のキーを付与します。同じキーで2回目の送信があった場合は「すでに作成済み」として処理をスキップします。
| キーの例 | 構成 | 用途 |
|---|---|---|
| comp1:invoice:001 | 会社ID + 伝票種類 + 伝票番号 | 請求書の重複防止 |
| comp1:delivery:2024-001 | 会社ID + 伝票種類 + 伝票番号 | 納品書の重複防止 |
7日間の記憶
結果は7日間キャッシュに保持されます。1週間以内であれば、「この請求書は作成済みかどうか」を確認できます。
キャッシュはRedis(分散キャッシュ)とメモリの2層構造。万が一Redisに接続できなくても、メモリキャッシュがバックアップとして機能します。
通信エラー時の自動リトライ
ネットワークの一時的な不調や、サーバーの混雑時には、自動的に少し待ってから再試行します。
指数バックオフとジッター
「指数バックオフ」は、リトライの間隔を徐々に長くする手法です。「ジッター」は、ランダムな遅延を加えることで、複数のクライアントが同時にリトライして再び混雑することを防ぎます。
API呼び出しを実行
429(レート制限)または5xx(サーバーエラー)
300ms + ランダム(0〜199ms)待機
600ms + ランダム待機
1200ms + ランダム待機
上限に達したらエラーを返却
リトライ可能なエラー
すべてのエラーでリトライするわけではありません。一時的なエラーのみリトライします。
| ステータス | 意味 | リトライ |
|---|---|---|
| 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枚作成されることはない
- 一時的障害への耐性: 自動リトライで回復
- 原因特定の容易さ: 構造化ログで問題箇所を即座に把握
現場担当者にとって
- 安心して操作できる: ミスしても大丈夫という安心感
- すぐに状況がわかる: ステータス表示で結果を確認
- 簡単に再実行できる: 修正して再送信するだけ