SDK
リトライと冪等性
何がリトライされ、何をあえてリトライしないのか、そしてリトライされた送信が重複しない理由。
送信
クライアントはすべての送信(emails.send、emails.sendBatch、templates.send)に Idempotency-Key を付与する。キーは**呼び出し**ごとに 1 回生成され、その呼び出しのリトライで再利用される。API は何かを送出する前にそのキーを確保するため、リトライは 2 通目を送るのではなく元のメッセージを再生する。一方で、意図的に send() を 2 回呼べば 2 通送られる。この 2 つは異なる意図であり、区別されたままになる。
この保証をプロセスをまたいで及ぼしたい場合は、独自の idempotencyKey を渡すこと。そうすれば、クラッシュして再実行されたジョブは送信を繰り返すのではなく再生する。
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 回試行する。 - リトライするのは、ネットワーク障害の後、または
408、500、502、503、504が返った場合だけである。429はRetry-Afterが付いている場合にのみリトライされるが、この API はそれを送らないため、レート制限は即座に例外となる。その他のステータスも直ちに例外となる。 - 0.5 秒から 8 秒まで指数的に増やし、ジッターを加える。復旧時に多数のインスタンスが再び同期しないようにするためである。
Retry-Afterがあればその指示に従う。delay-seconds 形式と HTTP-date 形式のどちらにも対応する。サーバーが待機時間を指定した場合、クライアントはバックオフではなくその時間だけ正確に待つ。- サーバーが 1 分を超える待機を要求した場合は、待機せよという指示ではなく中止せよという指示として扱い、
retryAfterSecondsを付けたエラーを送出する。要求より早く再試行することは、その指示に従ったことにはならない。 - 呼び出し側の
AbortSignalによるものはリトライされない。中断すると、リクエスト中であれ次の試行前の待機中であれ、直ちにOpenEmailNetworkErrorが送出される。