Requisitos e arquitetura de infraestrutura de webhooks

Resumo: ao criar um serviço online, lançar a aplicação é a parte fácil. Manter a aplicação no ar e os usuários satisfeitos é a verdadeira prova de que ela realmente se estabeleceu no mundo da entrega de serviços online.

Serviços online tendem a crescer bem rápido quando entregam valor que resolve alguma dor dos usuários. Como diz o ditado, “se você construir, eles virão”, e quando os usuários começam a inundar o seu serviço, a infraestrutura antes suficiente pode começar a ceder.

Conforme o tráfego cresce, cada componente da sua infraestrutura precisa ser escalado (termo usado aqui de forma ampla para representar qualquer estratégia, atividade, cultura ou verificação empregada) para acompanhar a pressão crescente.

Os webhooks, uma tecnologia de comunicação baseada em HTTP usada para trocar informações entre aplicações em rede, não são exceção a essa demanda por escala.

Webhooks dependem fortemente da rede e, por isso, carregam a bagagem de sempre: redes que não são 100% confiáveis, problemas de latência, banda limitada, redes inseguras e o custo do transporte de dados (entre outros).

Este artigo leva você por uma série de passos para encontrar uma solução que sustente webhooks em um ambiente de produção. Começamos com uma declaração de problema feita por especialistas do domínio e a destrinchamos para identificar as funcionalidades essenciais que a nossa solução precisa ter. Por fim, propomos um design arquitetural de alto nível que garante a performance ideal dos webhooks em produção.

Infraestrutura de webhooks, gerenciada para você.

A Hookdeck cuida do enfileiramento, da entrega e da observabilidade — para você focar em construir o seu produto.

Entendendo o problema do domínio: confiabilidade para webhooks em produção

Para começar, vamos deixar de lado por ora os inúmeros problemas do uso de webhooks em produção e olhar para o que seria uma configuração ideal. Para dar uma boa ideia disso, conversei com especialistas do universo dos webhooks para entender os problemas que já enfrentaram e anotei o que gostariam de ver em uma infraestrutura ideal.

Depois de algumas discussões interessantes, consegui condensar as informações que recebi na declaração de problema abaixo:

O sistema de gestão de webhooks proposto pretende servir como ponto centralizado para gerenciar webhooks de todos os provedores externos, além de ser confiável o suficiente para nunca perder um webhook. Queremos conseguir lidar com volumes variados de carga desenhando um sistema elástico o bastante para se ajustar ao tráfego do negócio. O sistema também precisa ser tolerante a falhas e dar visibilidade sobre todo o ciclo de vida de um webhook. As peculiaridades da operação de cada provedor externo devem ser abstraídas em um único workflow de webhooks, um sistema centralizado de verificação e um formato de payload unificado.

Os workflows relacionados à recuperação de falhas (alertas, retries etc.) também devem ser customizáveis conforme a importância do webhook para o sucesso do sistema.

No fim, queremos um sistema confiável e resiliente em que as informações dos webhooks sejam facilmente destiladas para cada parte interessada, seja na integração de novos membros do time, no suporte tentando resolver um problema ou nos desenvolvedores querendo saber o status de um webhook com uma rápida olhada nos relatórios.

Há muita coisa para desempacotar aqui, e alguns dos temas podem acabar na lista de desejos. No entanto, não vamos tomar decisões imediatas nem tirar conclusões apressadas; em vez disso, vamos deixar os dados falarem. Na próxima seção, destrincho essa declaração e mapeio os requisitos em termos arquiteturais que possam ser melhor compreendidos pelos arquitetos, engenheiros e desenvolvedores que vão agir.

Traduzindo as preocupações do domínio de webhooks em características arquiteturais

Agora que temos a nossa declaração de problema, vamos extrair dela os requisitos-chave da solução proposta. Lendo o texto, as seguintes funcionalidades se destacam:

  • Nunca perder um webhook
  • Lidar com carga variável de webhooks
  • Ter visibilidade sobre todo o ciclo de vida do webhook
  • Receber alertas quando houver problemas
  • Reenviar webhooks com falha
  • Centralizar a gestão de webhooks de todos os serviços externos criando um workflow único para cada webhook
  • Verificação em uma única plataforma
  • Formato de payload unificado
  • Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócio

A lista acima torna os requisitos mais visíveis do que parágrafos de texto corrido. Agora podemos atacar cada requisito para determinar o quão viável é atendê-lo.

Na hora de propor soluções, as partes interessadas e os arquitetos/engenheiros falam línguas diferentes. Enquanto os primeiros usam termos como “satisfação do usuário”, “time to market” e “prazo e orçamento”, os segundos falam de características arquiteturais como escalabilidade, disponibilidade, testabilidade e facilidade de deploy.

Então o nosso próximo passo é destilar esses requisitos até as características arquiteturais em que se encaixam. Note que um requisito pode se encaixar em uma ou mais características.

Requisitos do sistema

O detalhamento dos requisitos em características está na tabela abaixo:

  • Características operacionais aparecem em preto
  • Características estruturais/implícitas aparecem destacadas
Requisito do sistemaCaracterística(s) arquitetural(is)
Nunca perder um webhookConfiabilidade, performance, disponibilidade
Lidar com carga variável de webhooksEscalabilidade, confiabilidade
Ter visibilidade sobre todo o ciclo de vida do webhookSuportabilidade/monitoramento
Receber alertas quando houver problemasSuportabilidade/monitoramento, recuperabilidade, disponibilidade
Reenviar webhooks com falhaRecuperabilidade, robustez, continuidade, tolerância a falhas
Centralizar a gestão de webhooks de todos os serviços externos criando um workflow único para cada webhookSimplicidade, adaptabilidade, usabilidade
Verificação em uma única plataformaSegurança, simplicidade
Formato de payload unificadoSimplicidade
Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócioConfigurabilidade, tolerância a falhas

Definições das características arquiteturais

Atributo de designDetalhes
DisponibilidadePor quanto tempo o sistema precisa estar disponível (se for 24/7, é preciso ter medidas que permitam colocá-lo de volta no ar rapidamente em caso de falha).
ContinuidadeCapacidade de recuperação de desastres.
PerformanceMedida de eficiência em relação à quantidade de recursos usados sob condições conhecidas. Inclui testes de estresse, análise de picos, análise da frequência de uso das funções, capacidade necessária e tempos de resposta.
RecuperabilidadeRequisitos de continuidade do negócio (por exemplo, em caso de desastre, em quanto tempo o sistema precisa estar online de novo?). Isso afeta a estratégia de backup e os requisitos de hardware duplicado.
Confiabilidade/segurançaAvalia se o sistema é fail-safe (se consegue voltar a uma condição segura em caso de pane ou mau funcionamento). Ou se é crítico a ponto de afetar negativamente o negócio; por exemplo, a empresa vai perder grandes somas de dinheiro?
RobustezCapacidade de lidar com erros e condições de contorno durante a execução. Por exemplo, um erro de rede, serviços remotos falhando ou queda de energia.
EscalabilidadeCapacidade do sistema de manter performance e operação conforme o número de usuários ou requisições aumenta.
SegurançaOs dados precisam ser criptografados no banco (criptografia em repouso)? Criptografados na comunicação em rede entre sistemas (criptografia em trânsito)? Que tipo de autenticação precisa existir para acesso remoto etc.
Suportabilidade/monitoramentoO nível de suporte técnico exigido pela aplicação. Que nível de logging e outros recursos são necessários para depurar erros no sistema?
ConfigurabilidadeCapacidade dos usuários finais de alterar facilmente aspectos da configuração do software (por interfaces utilizáveis).
SimplicidadeFacilidade de uso do sistema no que diz respeito à experiência do desenvolvedor
Tolerância a falhasCapacidade de um sistema de continuar operando sem interrupção apesar da falha de um ou mais dos seus componentes.
AdaptabilidadeOs desenvolvedores conseguem adaptar o software de forma eficaz e eficiente a diferentes ambientes de hardware, software ou de uso em evolução?
UsabilidadeOs usuários conseguem usar o sistema de forma eficaz, eficiente e satisfatória para o propósito pretendido

Com a tabela acima, conseguimos visualizar o problema em termos técnicos e começar a discutir os componentes necessários na nossa arquitetura, além dos padrões de design mais adequados à solução proposta. Mas antes disso, precisamos priorizar.

Tentar atender a todas as funcionalidades, por mais desejáveis que sejam, nem sempre é viável. Características arquiteturais demais levam ao uso de soluções genéricas para resolver todo problema conhecido do domínio. Essas arquiteturas raramente funcionam e costumam levar a over-engineering.

Na próxima seção, vamos percorrer os requisitos para determinar quais funcionalidades são mais críticas para a performance dos nossos webhooks em produção.

Selecionando e priorizando os requisitos arquiteturais

Quando você está propondo uma solução para um problema, uma das maiores habilidades que pode ter é saber escolher as suas batalhas.

Como mencionado antes, tentar atender a todas as funcionalidades desejadas nem sempre é viável. Cada característica arquitetural suportada exige esforço de design e, talvez, suporte estrutural. Há também um problema maior: cada característica arquitetural impacta as outras. Por exemplo, colocar um load balancer entre um cliente e um pool de servidores ajuda a escalar o processamento das requisições, mas aumenta a latência por causa do componente intermediário.

Você precisa entender quais funcionalidades são mais importantes para os webhooks na sua infraestrutura e fazer trade-offs com as demais.

Para isso, é importante primeiro priorizar os requisitos de negócio da aplicação. Comece se perguntando o seguinte para cada requisito identificado:

Qual seria o custo de não implementar este requisito? O sistema vai quebrar? Perderíamos usuários ou dinheiro?

Para ajudar no detalhamento, temos três opções de resposta à pergunta acima. Com base nelas, cada requisito será categorizado como “Obrigatório” ou colocado em uma “Lista de desejos” (bom ter):

  • SIM — é uma funcionalidade operacional central cuja ausência leva ao colapso do sistema.
  • NECESSÁRIO — a ausência dessa funcionalidade não derruba o sistema, mas ela é necessária para dar suporte, investigar ou diagnosticar problemas que vão causar (ou já causaram) o colapso do sistema.
  • TALVEZ — a ausência dessa funcionalidade não derruba o sistema, mas ela pode ser usada para prevenir ainda mais problemas.
  • NÃO — essa funcionalidade é um luxo.

Um SIM vai para o balde “Obrigatório”. Um NECESSÁRIO fica com prioridade menor do que um SIM dentro do balde “Obrigatório”. Uma funcionalidade TALVEZ fica com prioridade menor do que uma NECESSÁRIO no balde “Obrigatório”, enquanto os requisitos com NÃO vão para o balde “Lista de desejos”.

Então vamos fazer isso com a nossa lista de requisitos para ver como ficam os baldes.

Requisitos obrigatórios do sistema

Requisito do sistemaRespostaBalde
Nunca perder um webhookSIMObrigatório
Lidar com carga variável de webhooksSIMObrigatório
Ter visibilidade sobre todo o ciclo de vida do webhookNECESSÁRIOObrigatório
Receber alertas quando houver problemasNECESSÁRIOObrigatório
Reenviar webhooks com falhaSIMObrigatório
Centralizar a gestão de webhooks de todos os serviços externos criando um workflow único para cada webhookNÃOLista de desejos
Verificação em uma única plataformaNÃOLista de desejos
Formato de payload unificadoNÃOLista de desejos
Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócioTALVEZObrigatório

Agora você tem uma boa ideia dos principais problemas que está tentando resolver. Resumindo, a lista a seguir mostra os requisitos selecionados em ordem de prioridade:

  • Nunca perder um webhook
  • Reenviar webhooks com falha
  • Lidar com a carga
  • Ter visibilidade sobre todo o ciclo de vida do webhook
  • Receber alertas quando houver problemas
  • Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócio

Esses são os problemas que vamos tentar resolver no design proposto para uma infraestrutura de webhooks padrão.

Propondo um design para otimizar a performance dos webhooks

Agora que temos a nossa lista final de funcionalidades, vamos mapeá-las de volta para as características arquiteturais em que se encaixam.

Requisito do sistemaCaracterística(s) arquitetural(is)
Nunca perder um webhookConfiabilidade, performance, disponibilidade
Reenviar webhooks com falhaRecuperabilidade, robustez, continuidade, tolerância a falhas
Lidar com a cargaEscalabilidade, confiabilidade
Ter visibilidade sobre todo o ciclo de vida do webhookSuportabilidade/monitoramento
Receber alertas quando houver problemasSuportabilidade/monitoramento, recuperabilidade, disponibilidade
Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócioConfigurabilidade, tolerância a falhas

Esta tabela vai servir como referência ao longo do design e da implementação da solução, incluindo todas as iterações do design, nesta série.

Antes de analisarmos cada requisito para descobrir o melhor componente ou grupo de componentes para o trabalho, vale lembrar de uma coisa: queremos desenhar a nossa arquitetura da forma mais iterativa possível.

Se tivermos um design fácil de alterar, podemos nos preocupar menos em acertar exatamente na primeira tentativa.

Nunca perder um webhook

Características arquiteturais:

  • Confiabilidade: queremos que os nossos webhooks sempre cumpram o seu propósito. Nenhum webhook deve se perder e todo webhook deve (em algum momento) causar o impacto pretendido na aplicação de destino. Para isso, precisamos de um sistema de logging para rastrear os webhooks de ponta a ponta e de um armazenamento temporário para guardar as informações do webhook até que o seu propósito seja cumprido.
  • Performance: os webhooks precisam ser atendidos a tempo para evitar timeouts. O processamento também deve usar os recursos do sistema com eficiência. Para isso, precisamos otimizar para tempos de resposta curtos, evitando tarefas longas ou a espera pela conclusão delas. Também precisamos de um pool distribuído de workers para processar os webhooks rapidamente.
  • Disponibilidade: os consumidores nunca devem estar indisponíveis para atender aos webhooks. Precisamos projetar com redundância.

Então, deste requisito saem os seguintes componentes:

  • Sistema de logging
  • Armazenamento temporário para guardar as informações dos webhooks
  • Sistemas de mensageria para processar webhooks de forma assíncrona
  • Balanceamento de carga no consumo de webhooks a partir do message broker

Reenviar webhooks com falha

O tema central de todas as características arquiteturais deste requisito é a tolerância a falhas. Em outras palavras, a capacidade de se recuperar da falha de um webhook, a continuidade apesar da falha e a consistência do estado da aplicação.

Para isso, primeiro queremos garantir que os consumidores de webhooks sejam stateless (o estado deve sempre ser mantido em armazenamentos externos, não na aplicação) e que o nosso processamento seja idempotente. Um tratamento adequado de erros também deve ser implementado nos consumidores para garantir que os erros sejam devidamente reportados aos handlers dentro da infraestrutura de webhooks.

Em seguida, precisamos de um componente e de um workflow que coletem os webhooks com falha e os passem para um sistema de retry onde possam ser reenviados.

Então, deste requisito saem os seguintes componentes:

  • Handlers de erro para falhas de webhook (os erros são reportados pelos consumidores)
  • Dead letter queues no message broker
  • Sistema de retry para webhooks com falha

Lidar com carga variável de webhooks

Este requisito grita escalabilidade.

Como mencionado antes, precisamos de um load balancer que distribua o tráfego entre um pool de consumidores uniformes. Esse pool pode ser expandido quando o tráfego aumenta, com a adição de mais instâncias da aplicação consumidora. Ele também pode ser reduzido, removendo instâncias quando o tráfego voltar aos números habituais.

Também vamos precisar de um rate limiter para controlar o tráfego que chega aos consumidores, entregando os webhooks a uma taxa compatível com a capacidade deles.

Então, deste requisito saem os seguintes componentes:

  • Balanceamento de carga no consumo de webhooks a partir do message broker
  • Rate limiter

Ter visibilidade sobre todo o ciclo de vida do webhook

Espera-se que o nosso webhook passe por vários componentes do design antes de chegar ao destino. Portanto, o design deve incluir um mecanismo para rastreá-lo da origem ao destino. Para isso, precisamos introduzir uma ferramenta de monitoramento e um trace ID para os nossos webhooks.

Isso vai permitir acompanhar o estado e o status do webhook de ponta a ponta dentro da infraestrutura.

Então, deste requisito saem os seguintes componentes:

  • Ferramenta de monitoramento
  • Trace ID

Receber alertas quando houver problemas

Precisamos ser alertados quando houver falhas ou quando o uso de algum recurso do sistema se aproximar de um limite que possa causar uma pane. Para isso, precisamos de um componente que colete métricas, um componente que reporte métricas e alertas configurados para qualquer métrica que exija atenção.

Também precisamos de um serviço de mensageria (e-mail, push etc.) que envie o alerta às pessoas certas, que precisam agir.

Então, deste requisito saem os seguintes componentes:

  • Componente de coleta de métricas
  • Reporte de métricas
  • Sistema de alertas
  • Serviço de mensageria para entregar alertas aos administradores

Configurar o comportamento do webhook (alertas, retries) com base na sua importância para o sucesso do negócio

Este é um daqueles requisitos para os quais não existe realmente um software de prateleira que atenda à necessidade. Talvez seja preciso construir um componente customizado. Essa solução vai trabalhar junto com o sistema de retry e de alertas, funcionando como um agendador configurável para as operações de alerta e de retry.

Então, deste requisito sai apenas um último componente necessário:

  • Sistema de agendamento configurável para alertar sobre problemas e reenviar webhooks

Diagrama da arquitetura proposta

A arquitetura proposta é mostrada no diagrama abaixo:

solução padrão de infraestrutura de webhooks

Note que esta é uma arquitetura provisória, sujeita a mudanças conforme descobrirmos novas informações ao longo desta série.

Vamos percorrer essa arquitetura e fazer uma breve visão geral dos componentes envolvidos.

Destrinchando o fluxo do design

Agora que sabemos como é a arquitetura proposta para a nossa solução de webhooks, vamos discutir como ela funciona.

Webhooks de diferentes origens passam por um API gateway que executa qualquer pré-processamento necessário na mensagem. É aqui que acontecem atividades como verificação, TLS termination, transformação de payload etc.

Como proxy de gateway, ele também ajuda a converter as mensagens HTTP (formato em que os webhooks são produzidos) em um protocolo suportado pelo message broker.

Em seguida, as mensagens de webhook são ingeridas e enfileiradas no message broker. Depois são roteadas com base nas regras de roteamento associadas a elas no momento da ingestão.

Essas mensagens são enviadas a um rate limiter que as repassa a uma taxa que o pool de consumidores consegue suportar. Um load balancer é colocado entre o rate limiter e os consumidores para distribuir a carga de webhooks.

Quando ocorre um erro enquanto um consumidor processa um webhook, ele reporta o erro na resposta ao load balancer, que então repassa as informações do webhook com falha ao sistema de retry para recolocá-lo na fila.

Para fins de monitoramento, puxamos logs e métricas de cada componente entre produtores e consumidores, usando um trace id para acompanhar o webhook enquanto ele passa por cada componente.

As informações desses logs e métricas serão então usadas para configurar alertas para os administradores.

No próximo artigo desta série, vamos dissecar cada componente, olhando para o seu propósito, configuração, considerações de caso de uso, opções de deploy e outras informações importantes sobre como ele lida com webhooks dentro do sistema.

Como a Hookdeck ajuda

Projetar uma infraestrutura de webhooks que atenda a todos os requisitos vistos neste guia (ingestão, fila, retry, monitoramento, segurança) é uma construção significativa que a maioria dos times descobre que precisa só depois do primeiro incidente em produção. O que começa como um único handler de endpoint vira filas, workers de retry, ferramentas de observabilidade, verificação de assinatura e runbooks operacionais — antes mesmo de você ter entregue a funcionalidade que os webhooks deveriam sustentar.

O Event Gateway da Hookdeck é uma infraestrutura de webhooks gerenciada que cuida da ingestão, da entrega com backpressure, dos retries, da observabilidade e da verificação de assinatura de forma nativa. Ele fica entre os seus provedores de webhooks e a sua aplicação como uma fila gerenciada, absorvendo picos de tráfego, armazenando entregas e dando um rastro completo de cada evento sem que você precise operar nada disso. Comece a usar a Hookdeck e pule os meses de trabalho de encanamento que uma infraestrutura de webhooks em produção normalmente exige.

Conclusão

Neste artigo, conseguimos sair do entendimento do que uma solução padrão de webhooks deveria ter até a proposta de uma solução. Isso foi feito com uma análise passo a passo do problema para descobrir quais são os requisitos técnicos e o que é necessário para lidar com webhooks de forma confiável.

A partir daqui, vamos usar o blueprint arquitetural da nossa solução para explorar os componentes envolvidos e diferentes estratégias de implementação.

Nos vemos no próximo capítulo, sobre os componentes da infraestrutura e suas funções.