Class RelayM2m
fixed-delay carrega o lote de saída
(PENDENTE, ERRO) abaixo do teto e despacha cada mensagem pela SPI tipada. Cada transição de
estado roda em transação curta própria (via MensageriaService, cross-bean) — isolamento por
mensagem: falha (ou exceção inesperada do enviador) marca só aquela linha, o lote segue.
Sob N réplicas do MESMO app o tick é serializado por advisory lock (GuardaCluster,
chave <app>_relay_m2m). O filtro por tipo do executar() separa apps
DIFERENTES; réplicas do mesmo app registram os mesmos tipos, casam o mesmo predicado e, sem a
guarda, entregam a mesma linha ao mesmo tempo — o efeito externo (o PUT) sai em dobro.
Contrato público — três pontos de entrada, de propósito distintos:
executar()— passe direto, SEM eleição. Drena o lote e pronto.executarSeEleito()— passe sob eleição: é o mesmo trabalho, mas só roda na réplica que ganha o advisory lock. É por aqui que o adotante exercita a guarda no teste dele.tick()— o disparo periódico (@Scheduled). Não é API: package-private, sem compromisso de SemVer; só aplica o gatemensageria.relay.enablede delega.
Isso remove a duplicação evitável, não a inerente: segue AT-LEAST-ONCE (crash entre a
resposta do destino e o commit ainda reentrega) e o receptor segue obrigado a deduplicar por chave
natural (decisão 0021). Não é lock de linha, e não pode ser: o relay seleciona fora de
transação e despacha cada mensagem na transação curta dela, então um FOR UPDATE SKIP LOCKED
no select seria solto antes do envio. Reivindicar por linha exigiria estado persistido (status
em-voo + marca de reivindicação + reaper de órfão) — o estado a mais que a 0021 descartou.
-
Constructor Summary
ConstructorsConstructorDescriptionRelayM2m(MensagemM2mRepository repositorio, RoteadorEnviadores roteador, MensageriaService servico, MensageriaConfig config, br.com.xadm.comum.mensageria.GuardaCluster guarda, String appName) -
Method Summary
Modifier and TypeMethodDescriptionintexecutar()Processa um lote de saída sem eleição: passe direto, para o teste e para um eventual "rodar agora".booleanProcessa um lote de saída sob eleição: adquire o advisory lock<app>_relay_m2me só então delega aoexecutar().
-
Constructor Details
-
RelayM2m
public RelayM2m(MensagemM2mRepository repositorio, RoteadorEnviadores roteador, MensageriaService servico, MensageriaConfig config, br.com.xadm.comum.mensageria.GuardaCluster guarda, @Value("${micronaut.application.name:app}") String appName)
-
-
Method Details
-
executarSeEleito
public boolean executarSeEleito()Processa um lote de saída sob eleição: adquire o advisory lock<app>_relay_m2me só então delega aoexecutar(). A réplica que não adquire coalesce (não roda, não enfileira) e o próximo passe reencaixa.É o seam da guarda: o adotante prova no teste dele que, com o lock ocupado por outra sessão, o relay não despacha — sem depender do agendador nem do
tick(), que não é API. O gatemensageria.relay.enablednão se aplica aqui (é do disparo periódico); a escotilhamensageria.relay.cluster-lock=falsesim: desligada a guarda, este método vira passe direto e retornatrue.- Returns:
truese rodou (ganhou o lock, ou a guarda está desligada);falsese coalesceu porque outra réplica detinha o lock.
-
executar
public int executar()Processa um lote de saída sem eleição: passe direto, para o teste e para um eventual "rodar agora". Quem precisa da guarda entre réplicas usaexecutarSeEleito().- Returns:
- quantidade de mensagens processadas neste passe.
-