پرش به مستندات
Ruby

تلاش مجدد و idempotency

چه چیزی دوباره تلاش می‌شود، چه چیزی عمداً نه، و چرا یک ارسالِ دوباره‌تلاش‌شده نمی‌تواند تکراری شود.

ارسال‌ها

کلاینت به هر ارسال (emails.send، emails.send_batch، templates.send و broadcasts.send) یک Idempotency-Key می‌چسباند که به‌ازای هر **فراخوانی** یک بار به شکل oe- و یک UUID تصادفی تولید می‌شود و همان فراخوانی در تلاش‌های دوباره‌اش از آن استفاده می‌کند. API پیش از آنکه چیزی را روانه کند آن کلید را ثبت می‌کند، پس یک تلاش دوباره همان پیام اصلی را بازپخش می‌کند نه اینکه پیام دومی بفرستد، در حالی که دو فراخوانی عمدی send همچنان دو بار می‌فرستند. این‌ها دو نیت متفاوت‌اند و متفاوت می‌مانند.

با دادن idempotency_key: خودتان، این تضمین را در میان فرایندها گسترش دهید، تا کاری که از کار افتاده و دوباره اجرا شده است ارسال‌هایش را بازپخش کند نه اینکه تکرارشان کند. بازپخش با replayed برابر true و پیام ذخیره‌شده در وضعیت کنونی‌اش پاسخ می‌دهد.

idempotency.rb
invoice_id = "inv_2026_09_4192" sent = client.emails.send(  from: "[email protected]",  to: "[email protected]",  subject: "Your September invoice",  text: "Invoice attached.",  idempotency_key: "invoice:#{invoice_id}") puts sent[:id], sent[:replayed]

آن را از همان چیزی مشتق کنید که ارسال را لازم کرده است. هرگز از ساعت. استفادهٔ دوباره از یک کلید با بدنه‌ای متفاوت با یک 422 idempotency_key_reuse رد می‌شود، نه اینکه بی‌صدا بازپخش شود. کلید 1 تا 255 نویسه از حروف، ارقام، _، .، : یا - است، و هر چیز دیگری یک 400 invalid_idempotency_key است.

باقی موارد

هر GET دوباره تلاش می‌شود. یک نوشتن تنها جایی دوباره تلاش می‌شود که درخواست دومِ همسان نتواند معنایی متفاوت از اولی داشته باشد، و ارسال واجد شرایط است چون کلید idempotency آن یک تکرار را به بازپخش تبدیل می‌کند.

فراخوانیتلاش مجددچرا
هر GETبلهچیزی تغییر نمی‌کند.
emails.send, emails.send_batch, templates.send, broadcasts.sendبلهیک کلید idempotency، تکرار را به بازپخش تبدیل می‌کند.
emails.cancel, emails.reschedule, broadcasts.cancel, forms.pause, forms.resume, threads.restoreبلهیک تنظیم خالصِ حالتی نام‌برده.
threads.update, threads.trashبلهتنظیم برچسب است. دو بار اعمال کردنش همان یک بار اعمال کردن است.
threads.snooze, threads.unsnoozeبلهلحظهٔ بیدارباش در بدنه است، نه مشتق‌شده از زمان رسیدن.
emails.update, labels.update, webhooks.update, settings.update, roles.update, members.update, domains.update, domains.update_address, domains.update_address_forward, contacts.update, audiences.update, keys.update, forms.update, branding.update, threads.update_note, chats.rename, account.set_email_notification, account.set_push_muted, app_host.set, workspaces.set_activeبلهیک تنظیم خالصِ فیلدهای نام‌برده.
members.grant_address, members.grant_domain, rules.reorder, threads.reorder_notesبلهاعطا یک upsert است، و ترتیب به‌طور کامل بیان می‌شود.
templates.publish, forms.publish, imports.startبلهانتشار چیزی که از پیش منتشر شده است، یا آغاز ایمپورتی که از پیش آغاز شده است، همان را بدون تغییر برمی‌گرداند.
templates.preview, templates.render, broadcasts.preview, rules.testبلهرندر می‌کنند، می‌شمارند یا ارزیابی می‌کنند و چیزی نمی‌نویسند.
domains.verify, app_host.verify, senders.researchبلهبررسی تکراری چیزی جز زمان انجامش را تغییر نمی‌دهد.
contacts.save, contacts.set_audiences, contacts.remove_photo, contacts.block, contacts.unblock, contacts.delete_many, keys.revoke, files.revoke_link, files.revoke_all_links, app_host.delete, account.remove_photo, branding.remove_image, domains.remove_logo, domains.remove_logo_certificate, domains.remove_address_photo, account.accept_invitation, account.decline_invitation, forms.approve_submission, subscriptions.moveبلههرکدام نتیجهٔ نهایی را بیان می‌کند، پس فراخوانی دوم همان چیزی را به جا می‌گذارد که اولی به جا گذاشت.
audiences.add_contact, audiences.add_contacts, audiences.remove_contacts, audiences.import_contacts, suppressions.add, domains.create_addressبلهتکرار، کار فراخوانی اول را انجام‌شده می‌یابد و به‌جای دو بار انجام دادنش آن را گزارش می‌کند.
contacts.set_photo, account.set_photo, branding.upload_image, domains.set_logo, domains.set_logo_certificate, domains.set_address_photo, imports.upload_chunkبلهبایت‌هایی که دوباره فرستاده می‌شوند جایگزین چیزی می‌شوند که تلاش اول ذخیره کرده بود.
drafts.create, labels.create, webhooks.create, templates.create, rules.create, roles.create, temp_mail.create, files.uploadخیرتلاش مجدد دو شیء به جا می‌گذارد.
drafts.updateخیربه‌جای استفادهٔ دوباره از شناسه‌ای که فرستاده‌اید، شناسه را از نتیجهٔ هر نوشتن بخوانید.
drafts.delete, labels.delete, webhooks.delete, templates.delete, rules.delete, roles.delete, members.remove, members.revoke_address, temp_mail.delete, temp_mail.delete_messageخیرتلاش مجدد پس از گم شدن یک پاسخ، برای کاری که موفق شده است شکست گزارش می‌کند.
webhooks.rotate_secretخیرچرخش دوم، کلید مخفی‌ای را که تلاش اول برگردانده بود باطل می‌کند.
webhooks.testخیریک تحویل ساختگی دوم می‌فرستاد.
webhooks.replay_deliveryخیررویداد را بار دوم به گیرندهٔ شما می‌فرستاد.
emails.translate, emails.compose, emails.rewrite, emails.suggest_subjectخیرهرکدام فراخوانی مدل خرج می‌کند، پس تلاش دوباره پس از درخواستی بی‌پاسخ، همان پاسخ را دو بار می‌خرد.
security.begin_step_up, security.verify_step_upخیرتلاش دوباره ممکن است ایمیل دومی بفرستد یا تلاش دومی را روی کد مصرف کند.
هر فراخوانی دیگری که GET نیستخیریک بار فرستاده می‌شود، و شکست گزارش می‌شود نه تکرار.

بک‌آف

  • محدود به max_retries: روی کلاینت، که پیش‌فرضش دو تلاش اضافی است. max_retries: 0 تلاش‌های دوباره را خاموش می‌کند.
  • تنها پس از یک شکست شبکه یا یکی از 408، 500، 502، 503 یا 504. یک 429 فقط وقتی دوباره تلاش می‌شود که Retry-After داشته باشد، و این API چنین چیزی نمی‌فرستد، پس محدودیت نرخ بی‌درنگ raise می‌شود. هر وضعیت دیگری فوراً raise می‌شود.
  • نمایی از نیم ثانیه تا هشت ثانیه، با jitter: هر انتظار نقطه‌ای تصادفی میان نیمی از آن سقف و کل آن است، تا یک ناوگان هنگام بازیابی دوباره هم‌زمان نشود.
  • با Retry-After در هر دو شکلش تنظیم می‌شود، delay-seconds و HTTP-date. وقتی سرور مدت انتظاری را نام ببرد، کلاینت دقیقاً همان‌قدر صبر می‌کند به‌جای عقب‌نشینی نمایی.
  • سروری که بیش از یک دقیقه بخواهد، چنین تفسیر می‌شود که به کلاینت می‌گوید بایست، نه اینکه بخواب، پس خطا با retry_after_seconds روی آن raise می‌شود. زودتر از آنچه خواسته بازگشتن، احترام گذاشتن به آن نیست.
  • پایان مهلت هم یک شکست شبکه است مانند هر شکست دیگر، پس فراخوانی‌ای که تکرارش بی‌خطر است پس از آن دوباره امتحان می‌شود، و timeout: برای هر تلاش از نو اعمال می‌شود.
  • انتظارها فراخوانی‌های sleep درون همان فراخوانی هستند، پس ترد فراخواننده هم منتظر می‌ماند، و فراخوانی تنها وقتی آخرین تلاشش تمام شد برمی‌گردد یا خطا raise می‌کند.