Eu achei o bug: o XMPP não estava errado, era o Gajim O TEMPO TODO!

Durante dias mergulhei no inferno dos duplicados XMPP. Tudo parecia um problema grave de protocolo, falha no Openfire, bug nos stanzas, erro em plugins ou algum loop estranho causado por pacotes reenviados. Mas a verdade era mais simples. E mais revoltante:

O bug estava no Gajim, O TEMPO DE RESPOSTA ENTRE REQUISIÇÃO E RECEPTAÇÃO É LATENTE.


Sintoma

  • O cliente XMPP Gajim exibia mensagens duplicadas.
  • Mesmo com apenas uma sessão ativa.
  • Mesmo com stanza-id corretamente aplicado.
  • Mesmo sem MAM, Carbons ou mensagens offline configuradas.

Hipóteses testadas (e eliminadas à força de TRUNCATE):

  1. Reenvio pelo MAM (XEP-0313)
  2. Duplicação por Carbons (XEP-0280)
  3. Sessões simultâneas interferindo no fluxo
  4. Mensagens offline mal entregues
  5. Falha de identificação do stanza-id

Nenhuma delas se confirmou. Nem interceptadores, nem desativação de Carbons resolveu.


Diagnóstico final: o combo que realmente funcionou

A única maneira de parar a duplicação foi executar este comando devastador:

TRUNCATE TABLE ofMessageArchive;
TRUNCATE TABLE ofConversation;
TRUNCATE TABLE ofConParticipant;
TRUNCATE TABLE ofOffline;

Depois disso, o Gajim parou de exibir mensagens duplicadas.
Foi o único método 100% eficaz.


Confirmação cruzada com outros clientes

Ao testar os mesmos fluxos com Conversations (Android) e Dino (Linux), o problema desapareceu — mesmo com as tabelas cheias.

Ou seja: o problema não era o Openfire.
O problema era o Gajim, que por algum motivo exibia a mesma mensagem mais de uma vez por delay ou falha de deduplicação local.


Conclusão: o bug é do cliente, não do servidor

  • Openfire funcionando perfeitamente
  • Nenhuma falha no protocolo XMPP
  • stanza-id aplicado corretamente
  • Carbons e MAM não são os culpados

O Gajim atrasa a exibição ou trata mal mensagens reenviadas, mesmo quando idênticas.


Solução comprovada

Desabilitar Carbons? Não adianta.
Interceptar stanzas? Não resolve.
O que funciona de verdade:

TRUNCATE TABLE ofMessageArchive;
TRUNCATE TABLE ofConversation;
TRUNCATE TABLE ofConParticipant;
TRUNCATE TABLE ofOffline;

Essa é a forma garantida de impedir o Gajim de tropeçar nas próprias pernas.


Estratégia recomendada: replicar e limpar

Para manter logs e evitar duplicação:

  • Replicar os dados dessas tabelas para outra base ou tabela de arquivamento para arquivamento e logs
  • Truncar as originais periodicamente (ex: a cada 5, 10 ou 15 minutos)
  • Automatizar via script cron + dump

Isso mantém o histórico seguro e a experiência do usuário limpa.


Moral da história

Nem toda duplicação é bug de servidor. Às vezes é só o Gajim engasgando com a própria pressa.

Se você também está enfrentando isso, pare de suspeitar do Openfire.
A causa é o Gajim.
E o remédio é simples:

TRUNCATE TABLE ofMessageArchive;
TRUNCATE TABLE ofConversation;
TRUNCATE TABLE ofConParticipant;
TRUNCATE TABLE ofOffline;

Funciona. Testado. Confirmado.
E agora, documentado.

Rolar para cima