ドキュメント本文へスキップ
SDK

リトライと冪等性

何がリトライされ、何をあえてリトライしないのか、そしてリトライされた送信が重複しない理由。

送信

クライアントはすべての送信(emails.sendemails.sendBatchtemplates.send)に Idempotency-Key を付与する。キーは**呼び出し**ごとに 1 回生成され、その呼び出しのリトライで再利用される。API は何かを送出する前にそのキーを確保するため、リトライは 2 通目を送るのではなく元のメッセージを再生する。一方で、意図的に send() を 2 回呼べば 2 通送られる。この 2 つは異なる意図であり、区別されたままになる。

この保証をプロセスをまたいで及ぼしたい場合は、独自の idempotencyKey を渡すこと。そうすれば、クラッシュして再実行されたジョブは送信を繰り返すのではなく再生する。

idempotency.ts
await openemail.emails.send(message, { idempotencyKey: `invoice:${invoice.id}` })

キーは、その送信が必要になった原因から導出すること。時計から作ってはならない。同じキーを異なるボディで再利用した場合は、黙って再生されるのではなく idempotency_key_reuse で拒否される。

その他すべて

読み取りはすべてリトライされる。書き込みがリトライされるのは、同一のリクエストを 2 回目に送っても 1 回目と異なる意味になりえない場合だけである。送信がこれに該当するのは、冪等性キーが繰り返しを再生に変えるからである。

呼び出しリトライ理由
すべての読み取りする何も変化しないため。
`emails.send`, `emails.sendBatch`, `templates.send`する冪等性キーが繰り返しを再生に変えるため。
`emails.cancel`, `emails.reschedule`する名前の付いた状態を設定するだけの操作であるため。
`threads.update`, `threads.trash`するラベルの設定であり、2 回適用することは 1 回適用することに等しいため。
`threads.snooze`, `threads.unsnooze`する復帰時刻はボディに含まれており、到着時刻から導出されないため。
`labels.update`, `webhooks.update`, `settings.update`, `roles.update`, `members.update`する名前の付いたフィールドを設定するだけの操作であるため。
`members.grantAddress`, `rules.reorder`する付与は upsert であり、並び順は全体が明示されるため。
`templates.publish`するすでに公開済みの head を公開しても、そのまま返されるだけであるため。
`templates.preview`, `rules.test`する描画または評価を行うだけで、何も書き込まないため。
`drafts.create`, `labels.create`, `webhooks.create`, `templates.create`, `rules.create`, `roles.create`, `tempMail.create`しないリトライするとオブジェクトが 2 つ残るため。
`drafts.update`しない送った id を再利用するのではなく、各書き込みの結果から id を読み取ること。
`drafts.delete`, `labels.delete`, `webhooks.delete`, `templates.delete`, `rules.delete`, `roles.delete`, `members.remove`, `members.revokeAddress`, `tempMail.delete`, `tempMail.deleteMessage`しない応答が失われた後にリトライすると、成功した処理について失敗が報告されるため。
`webhooks.rotateSecret`しない2 回目のローテーションが、1 回目の試行で返されたシークレットを無効にするため。
`webhooks.test`しない2 つ目のテスト配信を送ってしまうため。
`emails.translate`しないモデルの呼び出しを消費するため、応答のなかったリクエストをリトライすると同じ答えに二重に課金されるため。
その他すべての書き込みしない1 回だけ送信され、失敗は繰り返されるのではなく報告されるため。

バックオフ

  • クライアントの maxRetries で上限が決まり、既定では追加で 2 回試行する。
  • リトライするのは、ネットワーク障害の後、または 408500502503504 が返った場合だけである。429Retry-After が付いている場合にのみリトライされるが、この API はそれを送らないため、レート制限は即座に例外となる。その他のステータスも直ちに例外となる。
  • 0.5 秒から 8 秒まで指数的に増やし、ジッターを加える。復旧時に多数のインスタンスが再び同期しないようにするためである。
  • Retry-After があればその指示に従う。delay-seconds 形式と HTTP-date 形式のどちらにも対応する。サーバーが待機時間を指定した場合、クライアントはバックオフではなくその時間だけ正確に待つ。
  • サーバーが 1 分を超える待機を要求した場合は、待機せよという指示ではなく中止せよという指示として扱い、retryAfterSeconds を付けたエラーを送出する。要求より早く再試行することは、その指示に従ったことにはならない。
  • 呼び出し側の AbortSignal によるものはリトライされない。中断すると、リクエスト中であれ次の試行前の待機中であれ、直ちに OpenEmailNetworkError が送出される。