Arquitetura de Ingestão Dual (Hybrid)
Este documento descreve a implementação da ingestão dual de eventos da Evolution API, utilizando simultaneamente Webhooks e RabbitMQ para garantir alta disponibilidade e tolerância a falhas.
Diagrama de Fluxo
sequenceDiagram
participant E as Evolution API
participant R as RabbitMQ (Exchange)
participant W as Worker (Consumer)
participant H as Webhook Handler (Fullstack)
participant RD as Redis (Lock/Metrics)
participant DB as Postgres (Database)
Note over E, DB: Fluxo Paralelo de Ingestão
rect rgb(230, 245, 255)
Note right of E: Canal 1: Webhook Direto
E->>H: POST /api/internal/webhook
activate H
H->>RD: Check Lock (SET NX)
H->>DB: Check Inbox (processedAt?)
alt Não Processado & Lock Adquirido
H->>DB: Salva Payload Cru (canal: WEBHOOK)
H->>H: Processa Lógica de Negócio
H->>DB: Marca processedAt = now()
H->>RD: Incrementa Métricas (webhook:processed)
H-->>E: 200 OK
else Já Processado ou Lock Ocupado
H-->>E: 200 OK (skipped)
end
H->>RD: Release Lock
deactivate H
end
rect rgb(240, 255, 240)
Note right of E: Canal 2: RabbitMQ
E-->>R: Publishes Event
R-->>W: Consumes Message
activate W
W->>RD: Check Lock (SET NX)
W->>DB: Check Inbox (processedAt?)
alt Novo Evento & Lock Adquirido
W->>DB: Salva Payload Cru (canal: RABBITMQ)
W->>H: Forward POST (already_saved: true)
activate H
H->>H: Processa Lógica de Negócio
H->>DB: Marca processedAt = now()
H-->>W: 200 OK
deactivate H
W->>RD: Incrementa Métricas (rabbitmq:forward_ok)
W->>W: Rabbit ACK
else Falha no Forward
W->>W: Rabbit NACK -> Retry Queue (DLX)
W->>RD: Metrics (rabbitmq:forward_fail)
else Lock Ocupado
W->>W: Rabbit NACK (Requeue)
end
W->>RD: Release Lock
deactivate W
end
rect rgb(255, 245, 230)
Note over W, DB: Reconciliador (Auto-Cura)
loop A cada 5 minutos
W->>DB: Busca eventos sem processedAt (> 2min)
W->>H: Re-envia Forward (already_saved: true)
end
end
Componentes Chave
1. Deduplicação em Duas Camadas
- Redis (Curto Prazo): Utiliza
SET NXcom TTL de 2 minutos para evitar que o Webhook e o RabbitMQ processem a mesma mensagem simultaneamente. - Database (Longo Prazo): A tabela
evolution_ingestion_eventsarmazena odedupKey(SHA-256) e a data de processamento. Qualquer canal que vir uma chave já marcada comprocessedAtignora a mensagem.
2. Idempotência do Webhook
O handler de webhook aceita a flag already_saved: true quando chamado internamente pelo Worker. Isso evita que o payload cru seja duplicado no banco de dados, enquanto garante que a lógica de negócio (roteamento, filtros, alertas) seja executada.
3. Autenticação Interna
As chamadas delegadas (Worker -> Webhook) são protegidas pelo header x-internal-webhook-secret, garantindo que apenas processos autorizados possam injetar eventos marcados como "já salvos".
4. Resiliência (Retry & Reconciler)
- Retry Queues: Falhas temporárias no repasse do Worker para o Webhook são tratadas via retentativas exponenciais no RabbitMQ (5s, 30s, 3m).
- Reconciliador: Caso o processo de um worker ou webhook crashe APÓS tomar o lock mas ANTES de finalizar, o Reconciliador identifica essas mensagens "presas" e as re-insere no fluxo.
5. Observabilidade
Todas as etapas incrementam métricas no Redis (ps:metrics:evolution:*), permitindo monitorar o volume e a saúde de cada canal de ingestão em tempo real.