Ves a la documentació
SDK

Reintents i idempotència

Què es reintenta, què deliberadament no, i per què un enviament reintentat no pot duplicar-se.

Enviaments

El client adjunta un Idempotency-Key a cada enviament (emails.send, emails.sendBatch i templates.send), generat un sol cop per **crida** i reutilitzat pels reintents d'aquella crida. L'API reserva aquesta clau abans de despatxar res, de manera que un reintent reprodueix el missatge original en lloc d'enviar-ne un segon, mentre que dues crides deliberades a send() continuen enviant dues vegades. Són intencions diferents i continuen sent diferents.

Passa el teu propi idempotencyKey per estendre aquesta garantia entre processos, de manera que una tasca que ha fallat i s'ha tornat a executar reprodueixi els seus enviaments en lloc de repetir-los.

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

Deriva-la d'allò que va fer necessari l'enviament. Mai d'un rellotge. Reutilitzar una clau amb un cos diferent es rebutja amb idempotency_key_reuse en lloc de reproduir-se en silenci.

Tota la resta

Totes les lectures es reintenten. Una escriptura només es reintenta quan una segona petició idèntica no pot significar res diferent de la primera, i un enviament hi entra perquè la seva clau d'idempotència converteix una repetició en una reproducció.

CridaEs reintentaPer què
Totes les lecturesNo canvia res.
`emails.send`, `emails.sendBatch`, `templates.send`Una clau d'idempotència converteix una repetició en una reproducció.
`emails.cancel`, `emails.reschedule`És una assignació pura d'un estat amb nom.
`threads.update`, `threads.trash`És una assignació d'etiquetes. Aplicar-la dues vegades és aplicar-la un cop.
`threads.snooze`, `threads.unsnooze`L'instant de despertada és al cos, no es deriva de l'hora d'arribada.
`labels.update`, `webhooks.update`, `settings.update`, `roles.update`, `members.update`És una assignació pura de camps amb nom.
`members.grantAddress`, `rules.reorder`La concessió és un upsert, i l'ordre s'indica sencer.
`templates.publish`Publicar un head que ja està publicat el retorna sense canvis.
`templates.preview`, `rules.test`Renderitzen o avaluen, i no escriuen res.
`drafts.create`, `labels.create`, `webhooks.create`, `templates.create`, `rules.create`, `roles.create`, `tempMail.create`NoUn reintent deixa dos objectes.
`drafts.update`NoLlegeix l'id del resultat de cada escriptura en lloc de reutilitzar el que vas enviar.
`drafts.delete`, `labels.delete`, `webhooks.delete`, `templates.delete`, `rules.delete`, `roles.delete`, `members.remove`, `members.revokeAddress`, `tempMail.delete`, `tempMail.deleteMessage`NoUn reintent després d'una resposta perduda informa d'un error per a una feina que va tenir èxit.
`webhooks.rotateSecret`NoUna segona rotació invalida el secret que va retornar el primer intent.
`webhooks.test`NoEnviaria un segon lliurament sintètic.
`emails.translate`NoConsumeix crides al model, de manera que un reintent després d'una petició sense resposta paga dues vegades la mateixa resposta.
Qualsevol altra escripturaNoS'envia un sol cop, i un error s'informa en lloc de repetir-se.

El backoff

  • Limitat per maxRetries al client, amb dos intents addicionals per defecte.
  • Només després d'un error de xarxa o d'un 408, 500, 502, 503 o 504. Un 429 només es reintenta quan porta un Retry-After, i aquesta API no n'envia cap, així que un límit de freqüència llança l'error immediatament. Qualsevol altre estat llança l'error a l'acte.
  • Exponencial, de mig segon fins a vuit, amb jitter, perquè una flota no es torni a sincronitzar en la recuperació.
  • Regulat per Retry-After en qualsevol de les seves formes, delay-seconds i HTTP-date. Quan el servidor indica una espera, el client espera exactament això en lloc d'aplicar el backoff.
  • Un servidor que demana més d'un minut es tracta com si digués al client que s'aturi, no que dormi, de manera que l'error es llança amb retryAfterSeconds a sobre. Tornar abans del que ha demanat no és respectar-ho.
  • L'AbortSignal de qui crida mai no es reintenta. Avortar llança un OpenEmailNetworkError a l'acte, des de la petició o des de l'espera prèvia al següent intent.