Thử lại và idempotency
Cái gì được thử lại, cái gì cố tình không, và vì sao một lần gửi được thử lại không thể bị trùng.
Các lần gửi
Client gắn một Idempotency-Key vào mọi lần gửi (emails.send, emails.sendBatch và templates.send), sinh ra một lần cho mỗi **lời gọi** và được chính các lần thử lại của lời gọi đó dùng lại. API chiếm giữ khoá ấy trước khi điều phối bất cứ thứ gì, nên một lần thử lại sẽ phát lại thông điệp gốc thay vì gửi cái thứ hai, trong khi hai lời gọi send() có chủ ý vẫn gửi hai lần. Đó là hai ý định khác nhau và chúng vẫn được giữ khác nhau.
Hãy truyền idempotencyKey của riêng bạn để kéo dài bảo đảm đó xuyên qua các tiến trình, nhờ vậy một job bị sập rồi chạy lại sẽ phát lại các lần gửi thay vì lặp lại chúng.
await openemail.emails.send(message, { idempotencyKey: `invoice:${invoice.id}` })Hãy dẫn xuất nó từ chính thứ khiến lần gửi trở nên cần thiết. Đừng bao giờ dẫn xuất từ đồng hồ. Dùng lại một khoá với body khác sẽ bị từ chối với idempotency_key_reuse chứ không âm thầm phát lại.
Mọi thứ còn lại
Mọi thao tác đọc đều được thử lại. Một thao tác ghi chỉ được thử lại ở nơi một yêu cầu thứ hai giống hệt không thể mang nghĩa nào khác với yêu cầu đầu, và một lần gửi đủ điều kiện vì khoá idempotency biến một lần lặp thành một lần phát lại.
| Lời gọi | Có thử lại | Vì sao |
|---|---|---|
| Mọi thao tác đọc | Có | Không có gì thay đổi. |
| `emails.send`, `emails.sendBatch`, `templates.send` | Có | Một khoá idempotency biến một lần lặp thành một lần phát lại. |
| `emails.cancel`, `emails.reschedule` | Có | Một phép gán thuần tuý về một trạng thái có tên. |
| `threads.update`, `threads.trash` | Có | Một phép gán nhãn. Áp dụng hai lần cũng chính là áp dụng một lần. |
| `threads.snooze`, `threads.unsnooze` | Có | Thời điểm đánh thức nằm trong body, không phải suy ra từ thời điểm yêu cầu tới. |
| `labels.update`, `webhooks.update`, `settings.update`, `roles.update`, `members.update` | Có | Một phép gán thuần tuý các trường có tên. |
| `members.grantAddress`, `rules.reorder` | Có | Việc cấp quyền là một upsert, và thứ tự được nêu đầy đủ. |
| `templates.publish` | Có | Xuất bản một head vốn đã được xuất bản sẽ trả nó về nguyên vẹn. |
| `templates.preview`, `rules.test` | Có | Chúng chỉ kết xuất hoặc đánh giá, và không ghi gì cả. |
| `drafts.create`, `labels.create`, `webhooks.create`, `templates.create`, `rules.create`, `roles.create`, `tempMail.create` | Không | Một lần thử lại sẽ để lại hai đối tượng. |
| `drafts.update` | Không | Hãy đọc id từ kết quả của mỗi thao tác ghi thay vì dùng lại id bạn đã gửi. |
| `drafts.delete`, `labels.delete`, `webhooks.delete`, `templates.delete`, `rules.delete`, `roles.delete`, `members.remove`, `members.revokeAddress`, `tempMail.delete`, `tempMail.deleteMessage` | Không | Một lần thử lại sau khi mất phản hồi sẽ báo thất bại cho công việc vốn đã thành công. |
| `webhooks.rotateSecret` | Không | Một lần xoay khoá thứ hai sẽ làm vô hiệu bí mật mà lần đầu đã trả về. |
| `webhooks.test` | Không | Nó sẽ gửi một lần chuyển giao giả lập thứ hai. |
| `emails.translate` | Không | Nó tiêu tốn các lời gọi mô hình, nên một lần thử lại sau một yêu cầu không được trả lời chỉ mua cùng một câu trả lời hai lần. |
| Mọi thao tác ghi khác | Không | Gửi một lần, và một thất bại được báo cáo chứ không được lặp lại. |
Cơ chế giãn thời gian chờ
- Bị giới hạn bởi
maxRetriestrên client, mặc định là hai lần thử thêm. - Chỉ sau một sự cố mạng hoặc một
408,500,502,503hay504. Một429chỉ được thử lại khi nó mang theoRetry-After, mà API này không gửi header đó, nên một giới hạn tốc độ sẽ ném lỗi ngay. Mọi status khác đều ném lỗi lập tức. - Tăng theo cấp số nhân từ nửa giây lên tới tám giây, kèm jitter, để cả một đội máy không đồng bộ lại với nhau đúng lúc hệ thống hồi phục.
- Được điều nhịp bởi
Retry-Afterở cả hai dạng, số giây trễ và HTTP-date. Khi máy chủ nêu ra một thời gian chờ, client chờ đúng chừng ấy thay vì tự giãn thời gian. - Một máy chủ yêu cầu chờ lâu hơn một phút được hiểu là đang bảo client dừng lại chứ không phải ngủ, nên lỗi được ném ra kèm
retryAfterSeconds. Quay lại sớm hơn mức nó yêu cầu thì không phải là tôn trọng nó. AbortSignalcủa người gọi không bao giờ được thử lại. Huỷ sẽ ném ra mộtOpenEmailNetworkErrorngay lập tức, dù đang trong lúc gửi yêu cầu hay đang chờ trước lần thử kế tiếp.