Roteie um webhook para todo serviço que precisa dele
- 01Como origens, destinos e conexões se encaixam
- 02Filtrar quais eventos chegam a qual destino
- 03O que a distribuição faz com as novas tentativas, a vazão e a sua fatura
- 04Recuperar um destino sem afetar os outros
- 05Ler a fila enquanto ela escoa
Três objetos, e só três
Uma origem é um endpoint de entrada. Ela tem um maskId e uma ingestUrl, e essa URL é a única credencial de que o seu provedor precisa. Um destino é para onde você quer enviar eventos, com seus próprios cabeçalhos e seu próprio limite de taxa. Uma conexão liga uma origem a um destino e decide quais eventos fazem o trajeto.
A distribuição é o que você tem quando uma origem tem mais de uma conexão. Nada muda na origem, e o provedor nunca fica sabendo.
Conecte um segundo destino
Supondo que uma origem já exista, adicionar outro consumidor é um destino e uma conexão. Nenhum dos dois mexe no provedor.
- 1
Crie o destino
POST /v1/destinationscom a URL que você quer que seja chamada. Cabeçalhos personalizados são aceitos, e os que você marcar como sensíveis são criptografados em repouso e nunca retornados pela API. - 2
Conecte-o à origem
Uma conexão define o par e, opcionalmente, restringe o que passa por ela. Omita
filterRules.eventTypespara encaminhar tudo.curlcurl -s "$API/v1/connections" \ -H "authorization: Bearer $SDHK_KEY" \ -H 'content-type: application/json' \ -d '{ "name": "Stripe → billing service", "sourceId": "src_...", "destinationId": "dest_...", "filterRules": { "eventTypes": ["invoice.payment_succeeded"] } }'
- 3
Envie um evento de teste
Envie para a URL de ingestão da origem. Uma origem com verificação de assinatura configurada precisa de uma assinatura válida e, sem ela, a solicitação é respondida com 401 e armazenada com status
rejected. Quando um evento chega, você deve ver duas entregas associadas a ele, uma por conexão, cada uma com seu próprio status.
Filtrar sem uma linguagem de regras
Uma conexão faz a correspondência pelo tipo de evento e por nada mais. O tipo vem do eventTypeField da origem, um caminho em notação de ponto dentro da solicitação. Provedores conhecidos definem um padrão sensato, então uma origem GitHub lê headers.x-github-event e uma origem Stripe lê o tipo no corpo sem que você configure nada.
Essa única configuração cobre mais do que parece, porque é você quem escolhe o caminho. Aponte uma origem para body.action e as conexões dela filtram pela ação em vez do cabeçalho.
# A GitHub source filters on the event header by default.# Point eventTypeField at a body path to filter on something else:curl -s -X PATCH "$API/v1/sources/src_..." \ -H "authorization: Bearer $SDHK_KEY" \ -H 'content-type: application/json' \ -d '{ "data": { "eventTypeField": "body.action" } }' # Connections on that source now match on the action, not the header:# "filterRules": { "eventTypes": ["review_requested"] }
filtered. Você não o perdeu. Adicione a conexão que faltava e reenvie.Quanto custa distribuir
A unidade cobrada é a entrega, ou seja, um evento enviado a um destino conectado. Três conexões em um evento são três entregas. O preço acompanha o trabalho, não o número de assentos, então adicionar um quarto consumidor custa o mesmo, seja uma pessoa ou quarenta olhando o painel.
Quando um destino cai
As entregas falham de forma independente. Cada uma é tentada de novo em uma curva de backoff que começa em 5 segundos e se abre até 10 horas entre tentativas: três tentativas com teto de uma hora no Hobby, oito com teto de 36 horas nos planos pagos, que a curva atinge depois de cerca de 28 horas. Depois disso, ela espera por você em vez de desaparecer. As outras conexões do mesmo evento não são afetadas e já terão sido concluídas.
Nem toda resposta fora de 2xx conta como falha, o que importa quando você está lendo um log de tentativas às 3h da manhã.
Retry-After até uma hora e não custa nenhuma tentativa. São no máximo cinco esperas por entrega, e a espera é recusada antes disso se fosse ultrapassar o teto de novas tentativas do seu plano; em qualquer caso, a entrega segue para o caminho de falha.Existem dois caminhos de recuperação, e eles não são intercambiáveis. POST /v1/deliveries/{id}/retry reenvia uma entrega para um destino e não cria nada novo, então é grátis. POST /v1/events/{id}/replay passa o evento pelas conexões dele de novo, o que produz entregas novas e é cobrado. Use a nova tentativa quando um único consumidor falhou, e o reenvio quando você adicionou uma conexão depois.
rejected falhou na verificação de assinatura, então reenviá-lo empurraria conteúdo não verificado para os seus destinos em nome daquela origem. Isso retorna 400. Uma solicitação descartada como duplicata nem é armazenada, então também não há nada a reenviar.Cadência, que não é falha
Há dois limites de taxa no lado de saída: as entregas por segundo do seu plano e qualquer limite que você defina em um destino específico. Ultrapassar qualquer um deles coloca a entrega na fila em vez de fazê-la falhar. O status dela aparece como throttled, com throttledReason igual a rate_limit, nenhuma tentativa é gasta e ela é enviada quando houver capacidade. O mesmo status com destination_busy é o outro tipo de pausa: o destino a pediu com um 429, 502 ou 504.
Isso importa mais enquanto um destino está se recuperando. Um serviço que acabou de voltar não recebe todo o acúmulo de uma vez, e ninguém é acionado por uma fila que está escoando corretamente. Uma entrega que já foi retida mantém um timestamp throttledAt mesmo depois de ser concluída, então a pausa fica visível depois.
# Everything that was excluded by a filtercurl -s "$API/v1/events?status=filtered" -H "authorization: Bearer $SDHK_KEY" # What is waiting in the outbound queue right nowcurl -s "$API/v1/deliveries/stats" -H "authorization: Bearer $SDHK_KEY"→ { "pending": 4, "throttled": 412 }
Práticas que valem a pena
- Dê a cada consumidor sua própria conexão em vez de compartilhar uma e ramificar dentro do seu handler. Conexões separadas dão estados de novas tentativas separados e comprovantes separados.
- Defina um limite de taxa em qualquer destino que você sabe que é frágil. Para os dois lados, enfileirar sai mais barato que uma rajada de falhas seguida de backoff.
- Filtre na conexão, não no seu handler. Um evento que o seu serviço ia descartar ainda custa uma entrega se você deixá-lo passar.
- Consulte
?status=filteredquando um consumidor relatar eventos ausentes. A causa mais comum é umeventTypeFieldapontando para um lugar diferente do que você imaginava. - Torne os handlers idempotentes. O reenvio existe, as pessoas o usam durante incidentes, e o seu endpoint deve tratar uma segunda cópia como algo sem efeito.
Perguntas
Distribua uma origem para tudo o que precisa dela
Crie uma origem, adicione tantas conexões quanto forem os seus consumidores e acompanhe cada uma se estabilizar.