تلاش مجدد و idempotency
چه چیزی دوباره تلاش میشود، چه چیزی عمداً نه، و چرا یک ارسالِ دوبارهتلاششده نمیتواند تکراری شود.
ارسالها
کلاینت به هر ارسال (emails.send، emails.sendBatch و templates.send) یک Idempotency-Key میچسباند که بهازای هر **فراخوانی** یک بار تولید میشود و همان فراخوانی در تلاشهای مجددش دوباره از آن استفاده میکند. API پیش از آنکه چیزی را روانه کند آن کلید را ثبت میکند، پس یک تلاش مجدد همان پیام اصلی را بازپخش میکند نه اینکه پیام دومی بفرستد، در حالی که دو فراخوانی عمدی send() همچنان دو بار میفرستند. اینها دو نیت متفاوتاند و متفاوت میمانند.
با دادن idempotencyKey خودتان، این تضمین را در میان پروسهها گسترش دهید، تا کاری که کرش کرده و دوباره اجرا شده است ارسالهایش را بازپخش کند نه اینکه تکرارشان کند.
await openemail.emails.send(message, { idempotencyKey: `invoice:${invoice.id}` })آن را از همان چیزی مشتق کنید که ارسال را لازم کرده است. هرگز از ساعت. استفادهٔ دوباره از یک کلید با بدنهای متفاوت با idempotency_key_reuse رد میشود، نه اینکه بیصدا بازپخش شود.
باقی موارد
هر خواندنی دوباره تلاش میشود. یک نوشتن تنها جایی دوباره تلاش میشود که درخواست دومِ همسان نتواند معنایی متفاوت از اولی داشته باشد، و ارسال واجد شرایط است چون کلید idempotency آن یک تکرار را به بازپخش تبدیل میکند.
| فراخوانی | تلاش مجدد | چرا |
|---|---|---|
| هر خواندن | بله | چیزی تغییر نمیکند. |
| `emails.send`, `emails.sendBatch`, `templates.send` | بله | یک کلید idempotency، تکرار را به بازپخش تبدیل میکند. |
| `emails.cancel`, `emails.reschedule` | بله | یک تنظیم خالصِ حالتی نامبرده. |
| `threads.update`, `threads.trash` | بله | تنظیم برچسب است. دو بار اعمال کردنش همان یک بار اعمال کردن است. |
| `threads.snooze`, `threads.unsnooze` | بله | لحظهٔ بیدارباش در بدنه است، نه مشتقشده از زمان رسیدن. |
| `labels.update`, `webhooks.update`, `settings.update`, `roles.update`, `members.update` | بله | یک تنظیم خالصِ فیلدهای نامبرده. |
| `members.grantAddress`, `rules.reorder` | بله | اعطا یک upsert است، و ترتیب بهطور کامل بیان میشود. |
| `templates.publish` | بله | انتشار سری که از پیش منتشر شده است، همان را بدون تغییر برمیگرداند. |
| `templates.preview`, `rules.test` | بله | رندر یا ارزیابی میکنند و چیزی نمینویسند. |
| `drafts.create`, `labels.create`, `webhooks.create`, `templates.create`, `rules.create`, `roles.create`, `tempMail.create` | خیر | تلاش مجدد دو شیء به جا میگذارد. |
| `drafts.update` | خیر | بهجای استفادهٔ دوباره از شناسهای که فرستادهاید، شناسه را از نتیجهٔ هر نوشتن بخوانید. |
| `drafts.delete`, `labels.delete`, `webhooks.delete`, `templates.delete`, `rules.delete`, `roles.delete`, `members.remove`, `members.revokeAddress`, `tempMail.delete`, `tempMail.deleteMessage` | خیر | تلاش مجدد پس از گم شدن یک پاسخ، برای کاری که موفق شده است شکست گزارش میکند. |
| `webhooks.rotateSecret` | خیر | چرخش دوم، کلید مخفیای را که تلاش اول برگردانده بود باطل میکند. |
| `webhooks.test` | خیر | یک تحویل ساختگی دوم میفرستاد. |
| `emails.translate` | خیر | فراخوانی مدل خرج میکند، پس تلاش مجدد پس از درخواستی بیپاسخ، همان پاسخ را دو بار میخرد. |
| هر نوشتن دیگر | خیر | یک بار فرستاده میشود، و شکست گزارش میشود نه تکرار. |
بکآف
- محدود به
maxRetriesروی کلاینت، که پیشفرضش دو تلاش اضافی است. - تنها پس از یک شکست شبکه یا یکی از
408،500،502،503یا504. یک429فقط وقتی دوباره تلاش میشود کهRetry-Afterداشته باشد، و این API چنین چیزی نمیفرستد، پس محدودیت نرخ بیدرنگ throw میشود. هر status دیگری فوراً throw میشود. - نمایی از نیم ثانیه تا هشت ثانیه، با jitter، تا یک ناوگان هنگام بازیابی دوباره همزمان نشود.
- با
Retry-Afterدر هر دو شکلش تنظیم میشود، delay-seconds و HTTP-date. وقتی سرور مدت انتظاری را نام ببرد، کلاینت دقیقاً همانقدر صبر میکند بهجای عقبنشینی نمایی. - سروری که بیش از یک دقیقه بخواهد، چنین تفسیر میشود که به کلاینت میگوید بایست، نه اینکه بخواب؛ پس خطا با
retryAfterSecondsروی آن بالا میرود. زودتر از آنچه خواسته بازگشتن، احترام گذاشتن به آن نیست. AbortSignalیک فراخوان هرگز دوباره تلاش نمیشود. abort بیدرنگ یکOpenEmailNetworkErrorthrow میکند، چه از درخواست چه از انتظار پیش از تلاش بعدی.