Idempotência
Redes falham nos piores momentos: você faz POST de um envio, a conexão cai e agora você não sabe se o e-mail foi enviado. A idempotência permite que você retente essa requisição com segurança. Envie o mesmo header Idempotency-Key novamente e Bird reproduz a resposta original em vez de processar a requisição uma segunda vez.
Como funciona
A idempotência é opt-in. Adicione um cabeçalho Idempotency-Key a uma requisição POST, PATCH, PUT ou DELETE suportada. Requisições sem ele são processadas normalmente, sem deduplicação. Requisições GET ignoram o cabeçalho.
Na API do cliente, mutações com escopo de espaço de trabalho e de organização suportam o replay de resposta descrito abaixo. Operações restritas a usuário, sem escopo, não autenticadas e streams não passam por ele. Operações com um contrato de replay separado definem seu comportamento na respectiva página de referência. Por exemplo, Criar uma chamada de voz retém o snapshot de aceitação original para tentativas correspondentes quando você fornece uma chave.
Os SDKs geram uma chave para cada chamada de mutação e a reutilizam em tentativas automáticas, incluindo criação de chamadas. Você não precisa fornecer uma chave para tentativas automáticas do SDK. Forneça a sua própria quando uma operação pretendida abrange chamadas SDK separadas, como uma nova tentativa após reiniciar sua aplicação. Estes exemplos mostram esse caso.
await bird.email.send(
{
from: "hello@yourdomain.com",
to: ["delivered@messagebird.dev"],
subject: "Welcome!",
html: "<p>Thanks for signing up.</p>",
},
{ idempotencyKey: "welcome-user/usr_abc123" },
);client.email.send(
from_="hello@yourdomain.com",
to=["delivered@messagebird.dev"],
subject="Welcome!",
html="<p>Thanks for signing up.</p>",
options={"idempotency_key": "welcome-user/usr_abc123"},
)_, err := client.Email.Send(context.Background(), bird.EmailSendParams{
From: "hello@yourdomain.com",
To: []string{"delivered@messagebird.dev"},
Subject: "Welcome!",
HTML: "<p>Thanks for signing up.</p>",
}, option.WithIdempotencyKey("welcome-user/usr_abc123"))$bird->email->send(
from: 'hello@yourdomain.com',
to: ['delivered@messagebird.dev'],
subject: 'Welcome!',
html: '<p>Thanks for signing up.</p>',
options: new RequestOptions(idempotencyKey: 'welcome-user/usr_abc123'),
);curl -X POST https://us1.platform.bird.com/v1/email/messages \
-H "Authorization: Bearer $BIRD_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: welcome-user/usr_abc123" \
-d '{
"from": "hello@yourdomain.com",
"to": ["delivered@messagebird.dev"],
"subject": "Welcome!",
"html": "<p>Thanks for signing up.</p>"
}'Uma chave é qualquer string não vazia com até 255 caracteres. Um valor de cabeçalho vazio ignora a deduplicação. O formato recomendado é uma chave determinística derivada das suas próprias entidades, <event-type>/<entity-id> (por exemplo welcome-user/usr_abc123), para que tentativas entre reinícios de processo compartilhem a mesma chave; um UUID aleatório por operação lógica também funciona. Os SDKs Bird geram uma chave UUID automaticamente para cada requisição de mutação e a reutilizam em suas tentativas internas.
As chaves têm escopo no seu espaço de trabalho, ou na sua organização em endpoints de nível organizacional. Uma resposta concluída é mantida por 3 horas; uma retentativa após essa janela é processada como uma requisição nova. A janela cobre cronogramas típicos de retentativa. Nenhum registro de deduplicação permanece após a expiração.
Replays
Quando Bird encontra uma chave já concluída, retorna a resposta em cache, mesmo status code, mesmo corpo, sem reexecutar a requisição. Respostas reproduzidas incluem um header extra para que você possa diferenciá-las de um processamento novo:
Exemplo de código
HTTP/1.1 202 Accepted
Idempotency-Replay: trueRespostas retidas podem incluir rejeições 4xx. Use uma nova chave ao corrigir uma solicitação: se a rejeição foi retida, uma retentativa sem alteração a reproduz, e uma solicitação alterada retorna 409 E01005 IdempotencyKeyReuse. Respostas 5xx não são retidas, então faça a retentativa com a mesma chave e solicitação.
Modos de falha
| Cenário | Resposta |
|---|---|
| Mesma chave, mesma solicitação, original concluída | Resposta em cache reproduzida com Idempotency-Replay: true |
| Mesma chave, corpo da solicitação ou endpoint diferente | 409, E01005 IdempotencyKeyReuse |
| Mesma chave, solicitação original ainda em andamento | 409, E01004 RequestInProgress |
| Chave com mais de 255 caracteres em um endpoint que declara o header | 422, E01001 ValidationError |
| Proteção de idempotência indisponível antes da execução | 503, E01033 IdempotencyUnavailable; esta tentativa não é executada |
Reutilizar uma chave concluída com uma solicitação diferente é tratado como um bug do cliente: Bird retorna 409 imediatamente em vez de entregar silenciosamente uma resposta que não corresponde ao que você enviou. Gere uma nova chave para a nova solicitação. A comparação abrange o método, endpoint, parâmetros de path e query, e o corpo bruto da solicitação, incluindo espaços em branco JSON. Uploads multipart comparam nomes das partes, nomes de arquivos e conteúdos; boundaries e ordenação das partes não afetam a reprodução.
RequestInProgress significa que uma requisição concorrente com a mesma chave ainda não terminou, geralmente um timeout agressivo no lado do cliente retentando enquanto a primeira tentativa ainda está sendo processada. O lock em andamento expira em até 30 segundos, então aguarde brevemente e retente. Veja Errors para a resposta de erro que os envolve.
O que não é armazenado em cache
Respostas 5xx nunca são armazenadas em cache. A chave é liberada e Bird pode processar uma retentativa como uma nova tentativa. Retente respostas 5xx e timeouts com backoff usando a mesma chave e requisição. Uma operação pode ter efeito antes que sua resposta seja retida; se essa resposta for perdida, ou o lock em andamento expirar, uma retentativa pode executar a operação novamente.
Se a proteção de idempotência estiver indisponível antes da execução, API retorna 503 E01033 IdempotencyUnavailable sem executar esta tentativa. Mantenha a chave em toda retentativa. Este erro não descreve o resultado de uma tentativa anterior com a mesma chave.
Orientações práticas
- Gere uma chave por operação lógica e reutilize-a em toda tentativa HTTP dessa operação.
- Retente em erros de rede, timeouts e 5xx com backoff exponencial, reutilizando a mesma chave a cada vez.
- Trate 409 IdempotencyKeyReuse como um bug na sua geração de chaves. Não retente.
- Chaves são opcionais em mutações. Use uma quando precisar de proteção contra tentativas duplicadas; omita em requisições GET.
Próximos passos
- Referência de idempotência API: schemas de header e response-header
- Conceitos de SDK: geração automática de chaves e comportamento de retentativa nos SDKs
- Errors: a resposta de erro e o catálogo de códigos
- Envio de e-mail: endpoints de envio e lote
Recursos relacionados
Continue com a documentação, guias e exemplos sobre este tópico. Os recursos estão em inglês.