Pular para o conteúdo
ForceTricks
Voltar ao blog

Platform Events em Orgs Complexas: Além do Pub/Sub Básico

8 min de leitura
SérieSalesforce Orientado a EventosParte 1 de 1
  1. 1Platform Events em Orgs Complexas: Além do Pub/Sub Básico

A documentação faz Platform Events parecer simples: publica um evento, assina com um trigger, pronto. Esse modelo funciona bem para um padrão básico de notificação — um publisher, um consumer, volume baixo, falhas são aceitáveis.

Orgs complexas não são nada disso.

O Replay Buffer Não É Estratégia de Recovery

A janela de replay de 72 horas é frequentemente interpretada como "retry embutido." Não é. É um log ordenado de eventos que um subscriber pode rebobinar usando um ReplayId.

O que a janela significa na prática:

  • Eventos são retidos por 72 horas no event bus
  • Cada evento recebe um ReplayId monotonicamente crescente — não é um UUID, é um número de sequência por canal
  • Um subscriber pode solicitar eventos a partir de -2 (todos retidos), -1 (somente novos), ou de um ReplayId específico

A implicação operacional: se o trigger Apex subscriber falhar e você precisar fazer replay, vai fazer pelo Setup... exceto que não dá. Não existe UI para replay de eventos. Replay só está disponível via Streaming API (cliente CometD) ou Pub/Sub API. Se seu consumer é um Apex trigger, não há como reinjetar eventos perdidos — você precisaria construir um subscriber CometD separado.

Idempotência Não É Opcional

Qualquer consumer que receber eventos com replay -2 (ou qualquer rebobinagem pontual) vai reprocessar eventos que já foram tratados. Isso não é caso de borda — acontece toda vez que um subscriber se reconecta após uma pausa longa.

Projete cada consumer para ser idempotente desde o início. O padrão recomendado:

trigger OrderEventTrigger on Order_Event__e (after insert) {
    Set<String> correlationIds = new Set<String>();
    for (Order_Event__e evt : Trigger.new) {
        correlationIds.add(evt.Correlation_Id__c);
    }

    // Verifica quais correlationIds já foram processados
    Map<String, EventoProcessado__c> existentes = new Map<String, EventoProcessado__c>();
    for (EventoProcessado__c ep : [
        SELECT Correlation_Id__c FROM EventoProcessado__c
        WHERE Correlation_Id__c IN :correlationIds
    ]) {
        existentes.put(ep.Correlation_Id__c, ep);
    }

    List<EventoProcessado__c> paraInserir = new List<EventoProcessado__c>();
    for (Order_Event__e evt : Trigger.new) {
        if (existentes.containsKey(evt.Correlation_Id__c)) {
            continue; // já processado, ignora
        }
        // processa o evento...
        paraInserir.add(new EventoProcessado__c(
            Correlation_Id__c = evt.Correlation_Id__c
        ));
    }

    insert paraInserir;
}

O campo Correlation_Id__c no evento deve ser definido pelo publisher — um UUID ou um hash determinístico da chave de negócio. Nunca use o ReplayId para idempotência; ele muda se o evento for republicado.

Ordenação: Platform Events Não Têm Garantia

É aqui que arquitetos vindos de sistemas de mensageria como Kafka ou SQS FIFO se perdem. Platform Events não garantem a ordem de entrega dentro de um canal. Eventos publicados em sequência podem chegar fora de ordem no subscriber.

Na prática, a ordenação é geralmente preservada em fluxos de baixo volume — mas "geralmente" não é um contrato, e quebra sob carga.

Padrões de Design Quando a Ordem Importa

Números de sequência no payload do evento. O publisher estampa cada evento com um número de sequência monotônico com escopo em uma chave de negócio. O consumer bufferiza eventos fora de ordem e os processa em sequência:

// Publisher estampa a sequência
Integer proxSeq = getProximaSequencia(orderId); // mantido em objeto customizado
EventBus.publish(new Order_Event__e(
    Order_Id__c    = orderId,
    Sequencia__c   = proxSeq,
    Payload__c     = JSON.serialize(dadosMudanca)
));

O lado do consumer fica complexo rapidamente — bufferizar eventos desordenados em Apex é trabalhoso, especialmente sob o limite de 5 minutos do governor. Esse padrão funciona melhor quando o consumer é um sistema externo.

Envelope de evento com resolução de conflito. Em vez de processar eventos em ordem, projete o payload para ser autocontido o suficiente para que qualquer ordem produza o estado final correto. O padrão last-write-wins usando um timestamp Ultima_Modificacao__c no payload é a versão mais simples.

Use Change Data Capture quando a ordenação estrita for exigida. Eventos CDC para um determinado registro chegam na ordem da transação. Se você está rastreando transições de estado sequenciais em um objeto padrão, CDC é uma opção melhor que Platform Events — justamente porque você não controla o publisher.

Floods de Alta Volumetria

Um job em batch que processa 50.000 registros e publica um evento por registro vai atingir limites antes de terminar.

O lado da publicação: você pode publicar no máximo 150 eventos por transação com EventBus.publish(). Um batch com 50.000 registros precisa fragmentar as publicações em transações ou usar a Pub/Sub API via sistema externo.

O lado da assinatura: um Apex trigger em Platform Event é invocado com um lote de eventos — até 2.000 por invocação, mas sujeito aos limites de governor Apex padrão dessa invocação. Em alto volume, o event bus entrega eventos em uma taxa que respeita esses limites, o que significa que uma fila está se formando atrás do seu trigger.

O limite no nível da org que realmente importa: Event Delivery na UI de Org Limits (Setup > System Overview > Event Monitoring). A cota de entrega por hora padrão é 250.000 notificações de evento por hora na maioria das edições. Quando você atinge isso, a entrega enfileira silenciosamente. Nenhum erro explícito — os eventos simplesmente atrasam.

O modo de falha para projetar: um flood de 50.000 eventos às 9h não causa erros. Causa um backlog de processamento que dura horas e faz consumers em tempo real parecerem quebrados. Dimensione suas expectativas de volume de eventos contra essa cota horária.

Fan-Out: Um Publisher, Múltiplos Consumers

Platform Events são um ótimo fit para fan-out — um evento publicado, múltiplos consumers independentes. O problema surge quando esses consumers têm SLAs diferentes.

Um exemplo prático: um evento Pedido_Realizado__e consumido por três subscribers — detecção de fraude (deve completar em < 500ms), reserva de estoque (deve completar em < 2s), e sincronização com ERP que pode levar até 30 minutos.

Misturar esses consumers em um único Apex trigger cria um problema de acoplamento. Se a sincronização com ERP sofrer timeout, ela consome os limites de governor do trigger e potencialmente atrasa a detecção de fraude.

O design correto separa consumers por tier de SLA:

  • Síncrono/near-real-time: Apex trigger com budget de governor estrito
  • Async com SLA médio: Apex trigger separado, ou um segundo canal de Platform Event que o primeiro trigger republica
  • Long-running/externo: o Apex trigger chama um Queueable ou um endpoint REST, ou publica em um segundo canal consumido por uma camada de integração externa

Mantenha a cadeia de triggers rasa — republicar de um Platform Event para outro adiciona latência e dobra o consumo de cota de eventos.

Debugging de Platform Events em Produção

As ferramentas disponíveis:

  • Event Bus Stats (Setup > Platform Events > selecione o evento > Stats): mostra contagens de entregues/falhos e profundidade da fila. Útil para detectar backpressure.
  • Event Monitoring (requer licença add-on): o log EventDelivery captura erros de subscriber, timestamps de entrega e ReplayIds. Sem essa licença, a visibilidade de entregas com falha é mínima.
  • Debug Logs: se seu subscriber é um Apex trigger, o debug logging padrão se aplica. O desafio é correlacionar um evento específico a um debug log específico em alto volume.

A lacuna crítica: não existe inspetor de eventos no Setup. Você não consegue navegar pelo conteúdo do event bus. Não consegue fazer replay de eventos pelo Setup. A única forma de inspecionar payloads de eventos após o fato são os logs do Event Monitoring — e eles só existem se você tem a licença e o logging já estava habilitado.

A solução prática: registre o ReplayId e o Correlation_Id__c de cada evento recebido em seu objeto de log customizado imediatamente no recebimento, antes de qualquer processamento. Isso cria sua própria trilha de auditoria que não depende do Event Monitoring.

Quando Não Usar Platform Events

Platform Events são a ferramenta certa quando você precisa de entrega de eventos assíncrona, desacoplada e durável dentro ou entre sistemas Salesforce. São a ferramenta errada quando:

  • Você precisa de ordenação estrita em mudanças de estado de registro. Use Change Data Capture — é ordenado por registro e exige zero código no publisher.
  • Você precisa de integração ponto-a-ponto simples com um endpoint HTTP externo. Outbound Messaging é confiável, ordenado, at-least-once, e não exige código. Platform Events para esse caso de uso adiciona complexidade sem benefício.
  • Você precisa de notificações push em tempo real para a UI. A Streaming API (Generic Streaming ou PushTopics) tem menos overhead operacional para esse caso. Platform Events funcionam, mas são mais pesados.
  • O consumer precisa fazer callout para um sistema externo de forma síncrona. Um Apex trigger em Platform Event não pode fazer callouts. Você precisaria fazer a ponte via Queueable — e nesse ponto deve perguntar se o padrão original é o certo.

Dúvidas ou experiência diferente? Me encontre no LinkedIn.

Compartilhar
Gabriel Cruz Ferreira

Gabriel Cruz Ferreira

Salesforce Architect · 15x Certified · Rota para CTA

Este post foi útil?