Package br.com.xadm.comum.mensageria


package br.com.xadm.comum.mensageria
xadm-mensageria — entrega garantida M2M via outbox transacional (decisão 0021), como capacidade reusável da casa: uma tabela genérica (MensagemM2m), um relay @Scheduled com backoff/teto/PAUSADO (RelayM2m), uma SPI de envio tipado (EnviadorMensagem) que cada app implementa chamando o @Client gerado do OpenAPI, e uma tela /admin/mensageria (MensageriaController) restrita a admin @xadm.com.br (MensageriaAdminRule).

O motor é agnóstico de domínio; o dispatch é tipado (um bean EnviadorMensagem por tipo, no app). Semântica AT-LEAST-ONCE: o receptor deduplica por chave natural de negócio — a lib não faz dedup nem lock de linha (decisão 0021).

N RÉPLICAS do MESMO app (sobreposição de deploy, réplica) é caso à parte do bloco abaixo: o filtro por tipo separa apps DIFERENTES e não separa réplicas — as duas registram os mesmos tipos e casam o mesmo predicado. Por isso o tick() do RelayM2m roda sob advisory lock (<micronaut.application.name>_relay_m2m; escotilha mensageria.relay.cluster-lock=false): quem não adquire coalesce ao próximo tick. Isso mata a duplicação EVITÁVEL — as duas réplicas entregando ao mesmo tempo —, não a inerente: crash entre a resposta do destino e o commit ainda reentrega, e a idempotência do receptor segue obrigatória.

N apps DIFERENTES numa mesma mensagem_m2m (mesmo DB/schema): dois ownerships distintos. (1) Tabela (DDL): um app cria; os outros consomem (migração test-only pros testes standalone) — nunca dois CREATE. (2) Mensagem (roteamento): cada RelayM2m reivindica só os tipo que registra (RoteadorEnviadores.tiposRegistrados()) — app sem enviador é no-op. Assim os relays não competem (cada tipo tem 1 remetente); sem o filtro, o relay do app "errado" queimava a tentativa da linha alheia (dead-letter falso). Par disso: MensageriaService.enfileirar(String, String, String, String) falha-rápido se o tipo não tem enviador local (o remetente é quem enfileira). Não se resolve com config por-deploy (RELAY_ENABLED=false), coluna de origem, nem relay-broker único.

Schema é owned pelo app (sem Flyway na lib); o DDL canônico é publicado em db/mensagem_m2m.postgres.sql (índice (direcao, status, tipo) p/ o filtro do relay).