Skip to main content
Status: um registro de decisão, não um item de roadmap. Nada nesta página está implementado. Ela existe para que a próxima pessoa a perguntar “podemos rodar dois destes?” receba uma resposta real em vez de redescobrir as restrições pelo fonte.
Não, não hoje. Duas instâncias contra um mesmo banco descartarão a maior parte dos delivery receipts, e até recentemente duplicariam o crédito de cada top-up pré-pago. O que se segue é o porquê, e o que seria necessário. Para gateways independentes em um mesmo host — o que funciona — veja Várias instâncias.

O que já é seguro para cluster

Mais do que você esperaria. O caminho de envio foi construído sem pensar em cluster e mesmo assim está correto entre instâncias.

O que quebra

Dinheiro e registros

Perda de mensagens

Toda correlação de receipt vive em um armazenamento local ao nó.
  • Um receipt chegando em uma instância que não submeteu a mensagem não encontra nada, é descartado com uma única linha de log, e não produz nenhum receipt para o cliente, nenhum webhook e nenhuma linha cdr_final. Com N instâncias isso é aproximadamente (N−1)/N de todos os receipts.
  • O armazenamento adquire um file lock exclusivo. A segunda instância a subir no mesmo caminho falha, a falha é capturada, logada em WARN, e ela silenciosamente continua sem persistência alguma — então “duas instâncias compartilhando um diretório de dados” parece idêntico a “saudável”.
  • Receipts não empurrados são estacionados localmente, então um cliente reconectando em uma instância diferente nunca os recebe.
  • Sessões conectadas são rastreadas por JVM, então uma instância não pode saber que um cliente está conectado em outro lugar.

Mensagens concatenadas, concretamente

Segmentos chegando em instâncias diferentes nunca se reagrupam. Para uma mensagem de três segmentos dividida dois-e-um entre duas instâncias:
  • cada instância responde ESME_ROK e cobra pelos segmentos que recebeu;
  • cada uma espera o reassembling.timeoutMillis expirar, 30 segundos por padrão;
  • cada uma então transmite seus segmentos como fragmentos órfãos carregando um cabeçalho de concatenação para uma mensagem que nunca vai se completar.
O aparelho os mantém até que seu próprio timer expire e tipicamente não mostra nada. O cliente é cobrado pelos três. O único rastro é um aviso message.parts.incomplete por instância, nenhum dos quais sabe que o outro existe.
A sessão SMPP de um cliente é normalmente sticky no nível TCP, então isto morde em reconexão no meio de uma mensagem, em rebalance do load balancer, e em clientes mantendo vários binds que espalham segmentos entre eles.Whitelisting de conteúdo ainda se aplica ao que cada instância envia — o caminho de timeout é checado por conteúdo — então a falha é de entrega e cobrança, não de enforcement.

Degradado mas não perdido

TPS de fornecedor, rate limits de ingress, sampling de throughput e cursores de grupo de roteamento são todos por processo. N instâncias enviam até N × a taxa contratada para uma operadora. Isso é uma guarda contra um sender desgovernado, não uma quota distribuída — veja Limits.

O que seria necessário

Em linhas gerais: mover correlação de receipts e reassembly para storage compartilhado, dar a cdr_final uma chave única e um upsert, e tornar o sweeper leader-elected ou idempotente. Cada um é tratável; nenhum foi feito. Até lá, escale verticalmente, e use várias instâncias independentes onde o tráfego possa ser particionado por cliente.