fix: trata DisconnectReason.connectionReplaced e evita reconexoes concorrentes#2655
Open
PhyBruno wants to merge 6 commits into
Open
fix: trata DisconnectReason.connectionReplaced e evita reconexoes concorrentes#2655PhyBruno wants to merge 6 commits into
PhyBruno wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n-foundation Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…correntes Instancias especificas desconectavam diariamente sem intervencao do usuario. Causa raiz: DisconnectReason.connectionReplaced (440) nao estava na lista de codigos que interrompem a reconexao automatica, entao o socket tentava reconectar com credenciais ja invalidadas pela troca de sessao, gerando um ciclo close -> reconnect -> close. Alem disso, connectToWhatsapp/createClient nao tinham nenhum lock contra chamadas concorrentes: se uma reconexao manual (ex. via Chatwoot) disparasse enquanto a reconexao automatica do listener de 'close' ja estava em andamento, dois sockets Baileys podiam competir pela mesma sessao - um dos gatilhos conhecidos do proprio connectionReplaced. - Adiciona connectionReplaced a lista de codigos que nao devem reconectar automaticamente, com log explicito exigindo novo QR. - Adiciona lock de instancia (isConnecting) em createClient para impedir sockets concorrentes na mesma sessao.
Contributor
Reviewer's GuideAdds handling for Baileys DisconnectReason.connectionReplaced to avoid auto-reconnect loops and introduces an isConnecting guard in createClient to prevent concurrent socket connections on the same WhatsApp session. Sequence diagram for updated disconnect handling with connectionReplacedsequenceDiagram
participant Baileys
participant BaileysStartupService
Baileys->>BaileysStartupService: connection.update
alt [connection == close]
BaileysStartupService->>BaileysStartupService: determine statusCode
alt [statusCode == DisconnectReason.connectionReplaced]
BaileysStartupService->>BaileysStartupService: logger.warn (connection replaced)
BaileysStartupService->>BaileysStartupService: do not call connectToWhatsapp
else [statusCode in codesToNotReconnect]
BaileysStartupService->>BaileysStartupService: do not call connectToWhatsapp
else [statusCode not in codesToNotReconnect]
BaileysStartupService->>BaileysStartupService: connectToWhatsapp(phoneNumber)
end
else [connection != close]
BaileysStartupService->>BaileysStartupService: other connection.update handling
end
Sequence diagram for createClient isConnecting guard against concurrent reconnectssequenceDiagram
actor Integration
participant Baileys
participant BaileysStartupService
participant WASocket
Integration->>BaileysStartupService: connectToWhatsapp(number)
BaileysStartupService->>BaileysStartupService: createClient(number)
BaileysStartupService->>BaileysStartupService: set isConnecting = true
BaileysStartupService->>WASocket: makeWASocket(socketConfig)
BaileysStartupService->>BaileysStartupService: eventHandler()
BaileysStartupService->>BaileysStartupService: set isConnecting = false
Baileys-->>BaileysStartupService: connection.update (close)
BaileysStartupService->>BaileysStartupService: shouldReconnect?
alt [shouldReconnect]
BaileysStartupService->>BaileysStartupService: connectToWhatsapp(number)
BaileysStartupService->>BaileysStartupService: createClient(number)
alt [isConnecting == true]
BaileysStartupService->>BaileysStartupService: logger.warn (connection attempt already in progress)
BaileysStartupService-->>Integration: return existing client
else [isConnecting == false]
BaileysStartupService->>BaileysStartupService: set isConnecting = true
BaileysStartupService->>WASocket: makeWASocket(socketConfig)
BaileysStartupService->>BaileysStartupService: eventHandler()
BaileysStartupService->>BaileysStartupService: set isConnecting = false
end
else [!shouldReconnect]
BaileysStartupService->>BaileysStartupService: do not reconnect
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Contributor
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The
isConnectingguard increateClientreturnsthis.clientwhen a connection is already in progress, but this may still beundefinedfor the first concurrent caller; consider tracking and returning a shared connection Promise instead so callers always receive a valid socket or a clear error. - The log message for
DisconnectReason.connectionReplacedrepeats the literal code440; to avoid divergence if the enum changes, consider deriving the numeric code from the enum or centralizing the mapping so the message stays consistent with the actual value.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `isConnecting` guard in `createClient` returns `this.client` when a connection is already in progress, but this may still be `undefined` for the first concurrent caller; consider tracking and returning a shared connection Promise instead so callers always receive a valid socket or a clear error.
- The log message for `DisconnectReason.connectionReplaced` repeats the literal code `440`; to avoid divergence if the enum changes, consider deriving the numeric code from the enum or centralizing the mapping so the message stays consistent with the actual value.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problema
Em producao, observamos uma instancia especifica desconectando praticamente todo dia, sem nenhuma acao do usuario do lado do dispositivo.
Causa raiz
Em
whatsapp.baileys.service.ts, o handler deconnection.update(connection === 'close') tem uma listacodesToNotReconnectque nao incluiDisconnectReason.connectionReplaced(440 - emitido pelo Baileys quando a mesma sessao e assumida em outro lugar, ou por uma conexao concorrente). Isso faz o codigo tentar reconectar automaticamente com credenciais que a propria troca de sessao ja invalidou, gerando um cicloclose -> reconnect -> close.Agravante:
connectToWhatsapp/createClientnao tem nenhum lock contra chamadas concorrentes. Se uma reconexao manual (ex. disparada por uma integracao externa) ocorrer enquanto a reconexao automatica do listener decloseja esta em andamento, dois sockets Baileys podem competir pela mesma sessao - um gatilho conhecido do proprioconnectionReplaced.Mudancas
connectionReplacedadicionado acodesToNotReconnect, com log explicito avisando que a sessao foi assumida em outro lugar e que sera necessario um novo QR Code (evita reconectar em loop com credenciais ja invalidadas).isConnecting) emcreateClient, evitando que dois sockets sejam criados concorrentemente para a mesma instancia.Validacao
npx tsc --noEmit: sem erros.npx eslint --ext .ts src: sem erros/warnings.Relacionado: #2 (mesmo metodo
createClient, mudanca independente) e #3 (falhas relacionadas de QR/Chatwoot).Summary by Sourcery
Handle Baileys connection replacement as a terminal state and prevent concurrent WhatsApp reconnection attempts for the same instance.
Bug Fixes:
Enhancements: