Opakování a idempotence
Co se opakuje, co se záměrně neopakuje a proč opakované odeslání nemůže vytvořit duplikát.
Odesílání
Klient připojuje Idempotency-Key ke každému odeslání (emails.send, emails.sendBatch a templates.send); vzniká jednou pro každé **volání** a opakované pokusy téhož volání jej použijí znovu. API si klíč zamluví dřív, než cokoli odešle, takže opakování přehraje původní zprávu, místo aby odeslalo druhou, zatímco dvě záměrná volání send() pořád pošlou zprávu dvakrát. To jsou různé úmysly a různé i zůstanou.
Předejte vlastní idempotencyKey, a tuhle záruku roztáhnete i napříč procesy: úloha, která spadla a spustila se znovu, svá odeslání přehraje, místo aby je zopakovala.
await openemail.emails.send(message, { idempotencyKey: `invoice:${invoice.id}` })Odvozujte jej z toho, co odeslání vyvolalo. Nikdy z hodin. Použití téhož klíče s jiným tělem je odmítnuto chybou idempotency_key_reuse, nikoli tiše přehráno.
Všechno ostatní
Každé čtení se opakuje. Zápis se opakuje jen tam, kde druhý identický požadavek nemůže znamenat nic jiného než první, a odeslání tuto podmínku splňuje, protože jeho idempotenční klíč mění opakování v přehrání.
| Volání | Opakuje se | Proč |
|---|---|---|
| Každé čtení | Ano | Nic se nemění. |
| `emails.send`, `emails.sendBatch`, `templates.send` | Ano | Idempotenční klíč mění opakování v přehrání. |
| `emails.cancel`, `emails.reschedule` | Ano | Čisté nastavení pojmenovaného stavu. |
| `threads.update`, `threads.trash` | Ano | Nastavení štítků. Použít je dvakrát je totéž jako použít je jednou. |
| `threads.snooze`, `threads.unsnooze` | Ano | Okamžik probuzení je v těle, neodvozuje se z času doručení. |
| `labels.update`, `webhooks.update`, `settings.update`, `roles.update`, `members.update` | Ano | Čisté nastavení pojmenovaných polí. |
| `members.grantAddress`, `rules.reorder` | Ano | Udělení je upsert a pořadí se uvádí celé. |
| `templates.publish` | Ano | Publikování verze head, která už publikovaná je, ji vrátí beze změny. |
| `templates.preview`, `rules.test` | Ano | Jen vykreslují nebo vyhodnocují a nic nezapisují. |
| `drafts.create`, `labels.create`, `webhooks.create`, `templates.create`, `rules.create`, `roles.create`, `tempMail.create` | Ne | Opakování po sobě nechá dva objekty. |
| `drafts.update` | Ne | Id si načítejte z výsledku každého zápisu, místo abyste znovu používali to, které jste poslali. |
| `drafts.delete`, `labels.delete`, `webhooks.delete`, `templates.delete`, `rules.delete`, `roles.delete`, `members.remove`, `members.revokeAddress`, `tempMail.delete`, `tempMail.deleteMessage` | Ne | Opakování po ztracené odpovědi ohlásí selhání u práce, která uspěla. |
| `webhooks.rotateSecret` | Ne | Druhá rotace zneplatní tajný klíč, který vrátil první pokus. |
| `webhooks.test` | Ne | Odeslalo by druhé syntetické doručení. |
| `emails.translate` | Ne | Spotřebovává volání modelu, takže opakování po nezodpovězeném požadavku zaplatí tutéž odpověď dvakrát. |
| Každý jiný zápis | Ne | Odešle se jednou a selhání se ohlásí, místo aby se opakovalo. |
Backoff
- Omezeno hodnotou
maxRetriesna klientovi, ve výchozím stavu dva pokusy navíc. - Jen po selhání sítě nebo po
408,500,502,503či504.429se opakuje jen tehdy, když neseRetry-After, a toto API ji neposílá, takže překročení limitu vyhodí výjimku rovnou. Jakýkoli jiný stav vyhodí výjimku okamžitě. - Exponenciálně od půl sekundy do osmi, s jitterem, aby se celá flotila při zotavení znovu nesesynchronizovala.
- Tempo udává
Retry-Afterv kterékoli ze svých podob, delay-seconds i HTTP-date. Když server určí čekání, klient čeká přesně tak dlouho, místo aby couval podle vlastního backoffu. - Server, který si řekne o víc než minutu, se bere jako pokyn klientovi přestat, ne spát, takže se vyhodí chyba s
retryAfterSecondsna ní. Vrátit se dřív, než si řekl, není respektování jeho pokynu. AbortSignalod volajícího se nikdy neopakuje. Přerušení okamžitě vyhodíOpenEmailNetworkError, ať už z požadavku, nebo z čekání před dalším pokusem.