u/ClassroomFlashy9907

Estou construindo um ecossistema Multi-API onde uma API Central (Master) gerencia o saldo de créditos e distribui para APIs Satélites especializadas (emissão de Notas Fiscais, Boletos, etc.).

Contexto importante: cada crédito representa uma emissão de Nota Fiscal — inconsistência significa cobrar o cliente sem entregar o serviço, ou entregar sem cobrar. Precisa ser confiável.

Requisito principal: as Satélites devem operar normalmente mesmo se o Master estiver temporariamente offline.

Stack: NestJS + Fastify, Prisma (PostgreSQL), Redis, BullMQ.

---

Como está implementado hoje:

  1. Saldo local no Redis por satélite

credit:{idSystem}:master → saldo no painel

credit:{idSystem}:notas → saldo local da api-notas

  1. Transfer atômica entre Master e Satélite

const pipeline = redis.multi();

pipeline.decrby(`credit:${idSystem}:master`, credits);

pipeline.incrby(`credit:${idSystem}:notas`, credits);

await pipeline.exec();

  1. Consumo na Satélite (caminho quente — sem chamada HTTP ao Master)

await redis.decrby(`credit:${idSystem}:notas`, 1);

await this.consumptionLogRepo.save({ ...log, synced: false });

await this.syncQueue.add('sync-consumption', {

idempotencyKey: log.idConsumptionLog,

idSystem,

credits: 1,

}, { attempts: 5, backoff: { type: 'exponential', delay: 2000 } });

  1. Idempotência no Master

Antes de processar o job, o Master verifica se já recebeu aquele idempotencyKey — retries são seguros.

  1. Job de reconciliação (cron a cada 5 min)

Compara SUM dos ConsumptionLogs com synced=false contra o ApiBalance local. Se divergência > threshold, pausa emissões e alerta.

---

O que já descartei e por quê:

- Webhooks do Satélite para o Master: exige o Master online no momento da emissão — viola o requisito de independência.

- Pull periódico: latência alta, dashboard desatualizado, não escala bem.

- RabbitMQ: adiciona outro serviço quando Redis + BullMQ já está no stack.

---

Dúvida principal:

O maior risco que vejo é o job BullMQ esgotar os 5 retries silenciosamente (ex: Master fora por mais de X horas) e o saldo do Master ficar permanentemente divergente do real. Além da fila de dead-letter e do job de reconciliação, existe algum padrão consagrado para esse cenário? Alguém já operou algo parecido em produção?

Dúvidas secundárias:

- Em falha crítica do Redis, fazer fallback direto ao PostgreSQL em cada requisição pode gerar gargalo. Alguém já usou Circuit Breaker ou cache LRU em memória como camada intermediária nesse caso?

- Créditos separados por API (credit:sys:notas, credit:sys:boletos) vs. saldo global com distributed locks — para um sistema que vai crescer para 5-10 satélites, qual tende a ser mais simples de operar?

- Existe alguma estratégia mais eficaz do que a descrita acima para garantir resiliência total dos dados nesse tipo de arquitetura distribuída? Penso em padrões como Outbox Pattern, Event Sourcing ou Saga — mas não sei se o overhead vale para esse contexto. Alguém já comparou essas abordagens em produção?

- Como garantir que nenhuma operação (consumo, transferência, estorno) seja perdida no banco de dados em caso de falha parcial — por exemplo, o Redis sendo atualizado mas o INSERT no PostgreSQL falhando logo depois? Existe alguma forma de tornar essas duas operações atômicas entre si, ou a reconciliação periódica é o suficiente para cobrir esse gap?

reddit.com
u/ClassroomFlashy9907 — 8 days ago