Skip to content

Commit da27e2d

Browse files
committed
fix(chatwoot): implementa detecção correta de retry nos endpoints de envio
- Adiciona detecção de retry em textMessage() e mediaMessage() - Busca mensagens similares nos últimos 5 minutos no banco - Salva flag no cache quando detecta retry - Bloqueia webhook de retorno para evitar duplicação no Chatwoot
1 parent 8a6e77e commit da27e2d

5 files changed

Lines changed: 847 additions & 29 deletions

File tree

PREKEY_ERROR_FIX.md

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# Correção de Erros PreKeyError no WhatsApp - Com Recuperação de Mensagens
2+
3+
## Problema Identificado
4+
5+
O sistema estava apresentando erros intermitentes de `PreKeyError: Invalid PreKey ID` quando contatos específicos tentavam enviar mensagens. Este é um problema de criptografia end-to-end do WhatsApp onde:
6+
7+
- A sessão de criptografia entre o WhatsApp e um contato específico fica corrompida/dessincronizada
8+
- As Pre-shared Keys (PreKeys) usadas para estabelecer sessões E2E ficam inválidas
9+
- O contato tenta enviar mensagens com chaves antigas/inválidas
10+
- **PROBLEMA CRÍTICO**: As mensagens eram filtradas e descartadas permanentemente - o usuário nunca recebia essas mensagens
11+
12+
### Exemplo do Erro
13+
```
14+
PreKeyError: Invalid PreKey ID
15+
Contato: 250151964803283@lid / 556699840407@s.whatsapp.net
16+
Grupo: 556699841230-1508699495@g.us
17+
Tipo de mensagem: pkmsg (PreKey Message)
18+
```
19+
20+
## Solução Implementada
21+
22+
### 1. Armazenamento Temporário de Mensagens Falhas
23+
- Mensagens que falham na descriptografia são armazenadas temporariamente em memória (até 30 minutos)
24+
- Limite de 50 mensagens por contato para evitar uso excessivo de memória
25+
- Limpeza automática de mensagens antigas
26+
- **Nota**: Armazenamento em memória - mensagens são perdidas se o servidor reiniciar (mas isso é raro)
27+
28+
### 2. Rastreamento de Erros por Contato
29+
- Adicionado `preKeyErrorTracker` na classe `BaileysStartupService`
30+
- Rastreia quantas vezes cada contato gera erros de PreKey
31+
- Mantém timestamp do último erro para limpeza automática
32+
33+
### 3. Recuperação Automática de Sessão + Reprocessamento
34+
Novo método `attemptSessionRecovery()` que:
35+
- Detecta quando um contato tem 2+ erros de PreKey
36+
- Tenta reestabelecer a sessão usando `assertSessions()`
37+
- **NOVO**: Após recuperar a sessão, tenta reprocessar mensagens armazenadas
38+
- Limita tentativas a 3 para evitar loops infinitos
39+
- Após 3 falhas, descarta mensagens e reseta contador (permite novas tentativas imediatamente)
40+
41+
### 4. Reprocessamento de Mensagens Perdidas
42+
Novo método `retryFailedMessages()` que:
43+
- Tenta reprocessar até 3 vezes cada mensagem armazenada
44+
- Processa mensagens na ordem em que foram recebidas
45+
- Remove mensagens que foram processadas com sucesso
46+
- Descarta mensagens após 3 tentativas falhadas
47+
- **Resultado**: Mensagens que estavam "perdidas" são recuperadas!
48+
49+
### 5. Logs Melhorados
50+
- Logs detalhados identificando o contato problemático
51+
- Informações sobre grupo, participante e tipo de mensagem
52+
- Alertas específicos para erros de PreKey
53+
- Rastreamento de tentativas de recuperação
54+
- **NOVO**: Notificação quando mensagens são recuperadas com sucesso
55+
- **NOVO**: Alerta quando mensagens não podem ser recuperadas
56+
57+
### 6. Limpeza Automática
58+
- Erros antigos (>1 hora) são removidos automaticamente
59+
- Sessões recuperadas com sucesso limpam o contador de erros
60+
- Mensagens antigas (>30 minutos) são descartadas automaticamente
61+
- Cache de mensagens problemáticas expira em 30 minutos
62+
63+
## Arquivos Modificados
64+
65+
### `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts`
66+
1. **Linha ~231**: Adicionado `preKeyErrorTracker` e `failedMessages` para rastrear erros e armazenar mensagens
67+
2. **Linha ~5492**: Novo método `storeFailedMessage()` para armazenar mensagens que falharam
68+
3. **Linha ~5530**: Novo método `retryFailedMessages()` para reprocessar mensagens armazenadas
69+
4. **Linha ~5600**: Método `attemptSessionRecovery()` agora reprocessa mensagens após recuperar sessão
70+
5. **Linha ~5680**: Melhorado `baileysSignalRepositoryDecryptMessage()` com recuperação automática
71+
6. **Linha ~2292**: Filtro de mensagens agora armazena mensagens falhas para reprocessamento
72+
73+
### `src/api/integrations/channel/whatsapp/baileysMessage.processor.ts`
74+
1. **Linha ~58**: Melhorado `markMessageAsProblematic()` com logs de diagnóstico adicionais
75+
76+
## Como Funciona
77+
78+
### Fluxo Normal (Sem Erros)
79+
```
80+
Mensagem recebida → Descriptografia → Processamento → Sucesso
81+
```
82+
83+
### Fluxo com PreKeyError (Nova Implementação com Recuperação)
84+
```
85+
Erro 1 → Armazena mensagem em memória (30min)
86+
87+
Erro 2 → TENTA RECUPERAR SESSÃO automaticamente
88+
89+
Sessão recuperada → Reprocessa as mensagens → MENSAGENS CHEGAM! ✅
90+
91+
Falhou? → Tenta novamente no próximo erro
92+
93+
Erro 3 → Última tentativa de recuperação
94+
95+
Falhou 3x? → Descarta mensagens antigas + ZERA contador
96+
97+
Novas mensagens → Processo reinicia automaticamente (sem espera)
98+
```
99+
100+
### Detalhes do Processo
101+
102+
1. **Armazenamento Temporário**: Mensagens com erro são guardadas em memória por 30 minutos
103+
2. **Trigger de Recuperação**: Após 2 erros do mesmo contato, inicia tentativa automática
104+
3. **Limite de Tentativas**: Máximo de 3 tentativas de recuperação
105+
4. **Reset Inteligente**: Após 3 falhas, descarta mensagens antigas e zera contador
106+
5. **Sem Bloqueio**: Novas mensagens do mesmo contato podem acionar recuperação imediatamente
107+
6. **Prevenção de Duplicatas**: Sistema verifica `msg.key.id` antes de armazenar
108+
7. **Limpeza Automática**: Mensagens expiram após 30 minutos se não recuperadas
109+
110+
### Exemplo de Recuperação Bem-Sucedida
111+
```
112+
1. Contato envia 2 mensagens → Ambas falham (PreKeyError)
113+
2. Sistema armazena as 2 mensagens temporariamente (sem duplicação)
114+
3. Após 2º erro, sistema reestabelece sessão automaticamente
115+
4. Sistema reprocessa as 2 mensagens armazenadas
116+
5. Resultado: Ambas as mensagens são entregues com sucesso!
117+
```
118+
119+
## Benefícios
120+
121+
1. **Recuperação de Mensagens**: Mensagens que antes eram perdidas agora são recuperadas automaticamente
122+
2. **Recuperação Automática**: Sistema tenta resolver o problema sem intervenção manual
123+
3. **Logs Detalhados**: Facilita diagnóstico e identificação de contatos problemáticos
124+
4. **Proteção contra Loops**: Limites de tentativas evitam sobrecarga
125+
5. **Não Invasivo**: Mensagens continuam sendo filtradas até a recuperação
126+
6. **Limpeza Automática**: Não acumula dados de erros antigos
127+
7. **Transparente**: Usuário final não percebe o problema - mensagens chegam normalmente após recuperação
128+
129+
## Monitoramento
130+
131+
### Logs a Observar
132+
133+
**Erro detectado e mensagem armazenada:**
134+
```
135+
Erro de descriptografia (pkmsg) para 556699840407@s.whatsapp.net: PreKeyError: Invalid PreKey ID
136+
Mensagem armazenada para reprocessamento futuro. Contato: 556699840407@s.whatsapp.net, Total armazenado: 1
137+
```
138+
139+
**Tentativa de recuperação:**
140+
```
141+
Detectados 3 erros de PreKey para 556699840407@s.whatsapp.net. Tentando reestabelecer sessão...
142+
```
143+
144+
**Recuperação bem-sucedida:**
145+
```
146+
Sessão reestabelecida com sucesso para 556699840407@s.whatsapp.net
147+
Tentando reprocessar 3 mensagem(ns) armazenada(s) de 556699840407@s.whatsapp.net
148+
Mensagem reprocessada com sucesso! ID: 3EB0XXXXX
149+
Mensagem reprocessada com sucesso! ID: 3EB0YYYYY
150+
Mensagem reprocessada com sucesso! ID: 3EB0ZZZZZ
151+
3 mensagem(ns) recuperada(s) com sucesso de 556699840407@s.whatsapp.net!
152+
3 mensagem(ns) perdida(s) foi(ram) recuperada(s)!
153+
```
154+
155+
**Limite atingido após 3 tentativas (mensagens descartadas + contador resetado):**
156+
```
157+
ATENÇÃO: 5 mensagem(ns) de 556699840407@s.whatsapp.net não puderam ser recuperadas após 3 tentativas e serão descartadas.
158+
Contador resetado para 556699840407@s.whatsapp.net. Novas mensagens deste contato poderão acionar o processo de recuperação novamente.
159+
```
160+
161+
**Limite de armazenamento:**
162+
```
163+
Limite de mensagens armazenadas atingido para 556699840407@s.whatsapp.net. Mensagem será descartada permanentemente.
164+
```
165+
166+
## Limitações
167+
168+
1. **Janela de Recuperação**: Mensagens são armazenadas por até 30 minutos em memória
169+
2. **Limite por Contato**: Máximo 50 mensagens armazenadas por contato
170+
3. **Tentativas de Reprocessamento**: Máximo 3 tentativas por mensagem
171+
4. **Tentativas de Recuperação**: Máximo 3 tentativas, depois descarta e reseta contador
172+
5. **Memória**: Mensagens são armazenadas em memória RAM (perdidas se o servidor reiniciar, mas isso é raro)
173+
6. **Tempo de Recuperação**: Sistema tenta recuperar após 2 erros, geralmente em poucos segundos/minutos
174+
7. **Reset Automático**: Após 3 falhas, contador é zerado e novas mensagens podem acionar recuperação novamente
175+
176+
## Próximos Passos (Opcional)
177+
178+
Se o problema persistir ou para melhorar ainda mais:
179+
180+
1. **Persistência em Banco**: Armazenar mensagens falhas no banco de dados para sobreviver a reinicializações
181+
2. **Endpoint Manual**: Criar endpoint para forçar reset de sessão de contatos específicos
182+
3. **Webhook de Alerta**: Notificar administradores quando limite de tentativas for atingido
183+
4. **Métricas**: Adicionar contadores Prometheus para monitorar frequência de erros
184+
5. **Dashboard**: Interface para visualizar mensagens pendentes de recuperação
185+
6. **Notificação ao Usuário**: Informar o remetente que a mensagem está pendente de recuperação
186+
187+
## Testando a Solução
188+
189+
1. Monitore os logs após deploy
190+
2. Aguarde o próximo erro de PreKey do contato problemático
191+
3. Verifique se o sistema armazena a mensagem
192+
4. Após 2 erros, verifique se o sistema tenta recuperação
193+
5. Confirme se mensagens armazenadas são reprocessadas com sucesso
194+
6. Valide que as mensagens chegam ao destinatário final
195+
7. Se falhar 3 vezes, confirme que contador é resetado e novas mensagens são aceitas
196+
197+
## Comportamento Esperado
198+
199+
### Cenário 1: Recuperação Bem-Sucedida (Comum)
200+
```
201+
Erro 1 → Armazena mensagem
202+
Erro 2 → Tenta recuperar sessão → SUCESSO → Mensagens entregues ✅
203+
```
204+
205+
### Cenário 2: Recuperação na 3ª Tentativa
206+
```
207+
Erro 1 → Armazena mensagem
208+
Erro 2 → Tenta recuperar → Falha
209+
Erro 3 → Tenta recuperar → SUCESSO → Mensagens entregues ✅
210+
```
211+
212+
### Cenário 3: Falha Total (Raro)
213+
```
214+
Erro 1 → Armazena mensagem
215+
Erro 2 → Tenta recuperar → Falha
216+
Erro 3 → Tenta recuperar → Falha → Descarta mensagens antigas + Zera contador
217+
Nova mensagem → Processo reinicia (sem espera) → Nova tentativa de recuperação
218+
```
219+
220+
## Notas Técnicas
221+
222+
- `assertSessions()` força o WhatsApp a reestabelecer as chaves de criptografia
223+
- PreKey errors são esperados ocasionalmente em sistemas WhatsApp de alto volume
224+
- A solução não afeta o processamento normal de mensagens
225+
- Compatível com multi-tenant (isolamento por instância)
226+
- Mensagens são armazenadas com metadados completos para reprocessamento fiel
227+
- Reprocessamento usa o mesmo fluxo de mensagens normais (webhooks, integrações, etc.)

0 commit comments

Comments
 (0)