Analytics e Múltiplos Eventos

Papel do Analytics no ecossistema

Modelando o serviço de Analytics como consumidor de eventos de domínio.

Avançado 25 min 25 pontos Leitura 0%

Nesta aula você vai

  • Entender por que Analytics não deve consultar bancos de outros serviços
  • Definir contratos de evento que alimentam o read model
  • Criar pipeline inicial para processar order.created payment.approved e notification.sent

Papel do Analytics no ecossistema

Objetivos

  • Separar claramente modelo transacional e modelo analítico no monorepo.
  • Consumir eventos de order-service, payment-service e notification-service.
  • Construir a base para métricas quase em tempo real sem acoplamento de banco.

Pré-requisitos

  • Docker, Docker Compose e Kafka em execução.
  • Node.js 20+ no analytics-service.
  • Serviços do monorepo funcionando: customer (Java/Spring), order (Python/FastAPI), payment (Go/Gin), notification (Ruby/Sinatra).

Conceito

No e-commerce distribuído, analytics-service não pode fazer SELECT nos bancos dos outros contextos. A fonte oficial para leitura analítica é o fluxo de eventos. Nesta matéria, o analytics escuta:

  • order.created
  • payment.approved
  • notification.sent

Com isso, você monta um read model próprio, versionável e otimizado para consultas.

Estrutura de arquivos

services/analytics-service/
├── src/
│   ├── app.js
│   ├── consumers/
│   │   └── analytics-consumer.js
│   ├── handlers/
│   │   ├── order-created-handler.js
│   │   ├── payment-approved-handler.js
│   │   └── notification-sent-handler.js
│   └── store/
│       └── metrics-store.js
└── package.json

Passo a passo

  1. Crie o store em memória (simples para laboratório) em services/analytics-service/src/store/metrics-store.js:
const state = {
  totals: {
    orders: 0,
    paymentsApproved: 0,
    notificationsSent: 0,
  },
  revenueCents: 0,
  lastUpdatedAt: null,
};

export function incrementOrders() {
  state.totals.orders += 1;
  state.lastUpdatedAt = new Date().toISOString();
}

export function incrementPaymentsApproved(amountCents) {
  state.totals.paymentsApproved += 1;
  state.revenueCents += amountCents;
  state.lastUpdatedAt = new Date().toISOString();
}

export function incrementNotificationsSent() {
  state.totals.notificationsSent += 1;
  state.lastUpdatedAt = new Date().toISOString();
}

export function getMetricsSnapshot() {
  return structuredClone(state);
}
  1. Crie handlers por domínio:
// services/analytics-service/src/handlers/order-created-handler.js
import { incrementOrders } from "../store/metrics-store.js";

export async function handleOrderCreated(event) {
  if (!event?.payload?.orderId) return;
  incrementOrders();
}
// services/analytics-service/src/handlers/payment-approved-handler.js
import { incrementPaymentsApproved } from "../store/metrics-store.js";

export async function handlePaymentApproved(event) {
  const amountCents = Number(event?.payload?.amountCents ?? 0);
  incrementPaymentsApproved(amountCents);
}
// services/analytics-service/src/handlers/notification-sent-handler.js
import { incrementNotificationsSent } from "../store/metrics-store.js";

export async function handleNotificationSent(event) {
  if (!event?.payload?.channel) return;
  incrementNotificationsSent();
}
  1. Registre as rotas de tipo de evento em services/analytics-service/src/consumers/analytics-consumer.js:
import { handleOrderCreated } from "../handlers/order-created-handler.js";
import { handlePaymentApproved } from "../handlers/payment-approved-handler.js";
import { handleNotificationSent } from "../handlers/notification-sent-handler.js";

export const handlersByType = {
  "order.created": handleOrderCreated,
  "payment.approved": handlePaymentApproved,
  "notification.sent": handleNotificationSent,
};

Como testar

Suba o ambiente:

docker compose up -d kafka redis analytics-service notification-service payment-service order-service

Publique eventos de teste no tópico principal (via API dos serviços ou producer utilitário) e valide:

curl -s http://localhost:8085/health

Se o analytics-service subir sem erro e os handlers forem chamados, você já tem a fundação para as próximas duas aulas.

Dicas de projeto

  • Separe handler por evento para evitar switch gigante.
  • Não use o payload cru em toda a aplicação; normalize primeiro.
  • Deixe o read model idempotente desde o começo (vamos reforçar na aula 2).

Erros comuns

  • Ler banco do payment-service para calcular receita.
  • Não versionar contrato de evento.
  • Acoplar nome de tópico a regra de negócio.

Resumo

Você definiu o papel do analytics-service no ecossistema e criou a base de consumo de eventos order.created, payment.approved e notification.sent, sem dependência dos bancos transacionais.