Design clássico · Pleno
Entrega de webhooks (retries, assinatura, DLQ)
Projeto de entrevista clássico. Pontos centrais: agendamento de jobs e algoritmos de rate limiting.
Resposta curta
Projeto de entrevista clássico. Pontos centrais: agendamento de jobs e algoritmos de rate limiting. Na documentação da Stripe, a pessoa cadastra um endpoint HTTPS e, depois disso, a Stripe empurra dados em tempo real quando eventos acontecem na conta. O envio usa HTTPS e leva um JSON com as informações do evento.
01 · CONTEXTO E REQUISITOS
O que é entregar um webhook
Na documentação da Stripe, a pessoa cadastra um endpoint HTTPS e, depois disso, a Stripe empurra dados em tempo real quando eventos acontecem na conta. O envio usa HTTPS e leva um JSON com as informações do evento.
Para o remetente, que envia webhooks a muitos clientes, o problema se resume a perguntas de levantamento de requisitos: o que fazer quando o destino falha, como o destino sabe que o evento é legítimo, o que acontece se o mesmo evento chegar duas vezes e como o cliente descobre o que aconteceu com cada entrega. As seções seguintes tratam de cada uma.
02 · CONTRATO COM O DESTINO
O que conta como sucesso
O contrato de API com o destino é curto: a Stripe espera que o handler devolva rapidamente um código de sucesso (2xx), antes de qualquer lógica complexa que possa causar timeout. Redirecionamentos também contam como falha.
| Resposta do destino | Como a documentação da Stripe descreve |
|---|---|
| Não conecta | Não foi possível estabelecer conexão com o servidor de destino. |
| Redirecionamento (3xx) | Conta como falha. |
| Erro de cliente (4xx) | O servidor de destino não pode ou não quer processar o pedido. |
| Erro de servidor (5xx) | O servidor de destino encontrou um erro ao processar o pedido. |
| Erro de TLS | Não foi possível estabelecer uma conexão segura com o servidor de destino. |
| Timeout | O servidor de destino demorou demais para responder. |
Para o remetente, isso define o que o worker de entrega deve tratar como falha e reagendar: qualquer resposta que não seja o sucesso esperado, inclusive a ausência de resposta.
03 · ENTREGA, RETRY E DLQ
Da primeira versão ao pipeline com fila
A primeira versão é ingênua: o próprio serviço que gera o evento chama o endpoint do cliente dentro da mesma requisição.
O serviço gera o evento e chama diretamente o endpoint do cliente, esperando a resposta.
Se o destino for lento ou estiver fora do ar, o serviço fica preso nessa chamada e não há onde guardar o evento para tentar de novo.
A saída é desacoplar. A Stripe descreve o comportamento que um remetente precisa reproduzir: em modo live, as tentativas automáticas seguem por até três dias com backoff exponencial; entregas criadas em sandbox são repetidas três vezes ao longo de algumas horas. Se o destino estiver desabilitado ou apagado na hora do retry, as tentativas futuras daquele evento são impedidas.
O serviço grava o evento na fila de entregas e segue o fluxo principal sem esperar o cliente.
Um worker de entrega retira o evento da fila, assina a requisição e faz o POST no endpoint do cliente.
Quando o destino devolve sucesso, o worker marca a entrega como concluída no registro de entregas.
Quando o destino falha ou não responde, o worker devolve o evento à fila de reentrega, para ser tentado de novo mais tarde.
A fila de reentrega devolve o evento ao worker depois de uma espera, e o ciclo se repete.
Quando as tentativas se esgotam, o evento vai para a fila de falhas, onde fica guardado para análise e reenvio manual.
Além dos retries automáticos, a Stripe permite reenvio manual: pelo Dashboard, até quinze dias depois da criação do evento; pela CLI, até trinta dias. Reenviar à mão um evento que não chegou não cancela os retries automáticos, mesmo que o reenvio devolva um código 2xx.
04 · ASSINATURA E SEGURANÇA
Como o destino sabe que o evento é legítimo
A documentação da Stripe alerta que, sem verificação, um invasor poderia enviar eventos falsos ao endpoint para disparar ações como liberar pedidos, conceder acesso ou alterar registros. A proteção descrita é assinar cada evento, com a assinatura no header Stripe-Signature.
Cada endpoint tem o seu segredo, e o destino precisa do corpo bruto da requisição para verificar a assinatura. O timestamp vai no header e é verificado pela própria assinatura, e a aplicação pode rejeitar um payload cujo timestamp esteja velho demais; por padrão, as bibliotecas da Stripe aceitam cinco minutos de diferença. A cada nova tentativa de entrega, a Stripe gera uma nova assinatura e um novo timestamp.
| Mecanismo | O que a documentação diz |
|---|---|
| Segredo por endpoint | Cada endpoint tem um segredo único, e cada evento é assinado no header Stripe-Signature. |
| Timestamp assinado | O timestamp entra no header e é verificado pela assinatura. |
| Rotação de segredo | A expiração do segredo antigo pode ser adiada por até 24 horas; nesse período há vários segredos ativos e uma assinatura por segredo. |
| Lista de IPs | A Stripe envia os eventos de uma lista definida de endereços IP. |
05 · DUPLICATAS, ORDEM E O RECEBEDOR
Entrega repetida, sem ordem garantida
O endpoint pode receber o mesmo evento mais de uma vez. A defesa descrita é registrar os IDs dos eventos já processados e não processar de novo os que já constam. Em alguns casos, dois objetos Event separados são gerados e enviados; para identificar essas duplicatas, a documentação usa o ID do objeto em data.object junto com o tipo do evento.
A Stripe não garante a entrega na ordem em que os eventos foram gerados, e o destino não deve depender de uma ordem específica. Em vez de usar o campo created para decidir a ordem ou se algo já foi processado, a recomendação é acompanhar os IDs de evento. Se um evento chegar primeiro, é possível buscar pela API os objetos que faltam.
Do lado do recebedor, a documentação recomenda processar os eventos com uma fila assíncrona. Um grande pico de entregas, como no começo do mês, quando todas as assinaturas renovam, pode sobrecarregar os hosts do endpoint, e a fila permite processar os eventos no ritmo que o sistema suporta.
O endpoint recebe o POST, verifica a assinatura usando o corpo bruto e devolve sucesso logo.
O endpoint apenas coloca o evento na fila e responde; a lógica pesada fica para o worker.
Um worker consome da fila no ritmo que o sistema do cliente suporta.
O worker consulta o registro de IDs: se o evento já foi processado, ignora; se não, processa e registra o ID.
Se o remetente pode repetir envios, o recebedor precisa ser idempotente. Documente isso para os clientes e ofereça o ID do evento como chave de deduplicação.
06 · OBSERVABILIDADE E LIMITES
O que o cliente precisa enxergar, e o que fica de fora
A Stripe mostra, por endpoint, uma aba de entregas com a lista de eventos e se cada um está entregue, pendente ou falho. Ao abrir um evento, o cliente vê o status HTTP da tentativa e o horário das entregas pendentes. O cadastro também tem limite: até 16 destinos de eventos registrados.
Duas decisões de desenho merecem justificativa própria na entrevista: o agendamento das reentregas, isto é, quando cada evento volta à fila, e um limite de envio por destino, para que um cliente lento não consuma todos os workers.
Perguntas frequentes
O que é Entrega de webhooks (retries, assinatura, DLQ)?
Projeto de entrevista clássico. Pontos centrais: agendamento de jobs e algoritmos de rate limiting.
O que o design de Entrega de webhooks (retries, assinatura, DLQ) cobre?
Ele está organizado nestas seções: O que é entregar um webhook, O que conta como sucesso, Da primeira versão ao pipeline com fila, Como o destino sabe que o evento é legítimo, Entrega repetida, sem ordem garantida e O que o cliente precisa enxergar, e o que fica de fora.
Quanto tempo leva Entrega de webhooks (retries, assinatura, DLQ) e qual é o nível?
Leva cerca de 14 minutos para ler e tem nível Pleno.
Agora projete você mesmo
Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.