Repository navigation
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.
AlmogCohen
added a commit
to AlmogCohen/evolution-api
that referenced
this pull request
Sep 27, 2026
connect(), which both connectToWhatsapp (a new attempt, fresh QR budget) and the backoff reconnect go through, now runs one connect at a time: a connect that arrives while one is under way with the same number joins it and gets the same socket; one for a different number waits for it and then runs. createClient retires the previous socket before building the next: it first detaches Evolution from it (the ev.process subscription and the CB:call listeners), then ends it. The order matters: ending a live Baileys socket emits a close, and if Evolution were still listening that close would reconnect and end the new socket, the recreate loop upstream PR evolution-foundation#2656 has. A new socket also drops any reconnect still waiting on its backoff, since that reconnect was for the socket just replaced; a connect that fails before building one leaves it in place. Events are tied to the socket that emitted them: a batch from a socket that is no longer this.client is dropped, and connectionUpdate ignores a connection.update from a replaced socket even if it was queued before the switch. 440 stays reconnectable (PR evolution-foundation#2655 makes it final, which strands a valid session when the 440 came from our own duplicate socket). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AlmogCohen
added a commit
to AlmogCohen/evolution-api
that referenced
this pull request
Sep 27, 2026
connect(), which both connectToWhatsapp (a new attempt, fresh QR budget) and the backoff reconnect go through, now runs one connect at a time: a connect that arrives while one is under way with the same number joins it and gets the same socket; one for a different number waits for it and then runs. createClient retires the previous socket before building the next: it first detaches Evolution from it (the ev.process subscription and the CB:call listeners), then ends it. The order matters: ending a live Baileys socket emits a close, and if Evolution were still listening that close would reconnect and end the new socket, the recreate loop upstream PR evolution-foundation#2656 has. A new socket also drops any reconnect still waiting on its backoff, since that reconnect was for the socket just replaced; a connect that fails before building one leaves it in place. Events are tied to the socket that emitted them: a batch from a socket that is no longer this.client is dropped, and connectionUpdate ignores a connection.update from a replaced socket even if it was queued before the switch. 440 stays reconnectable (PR evolution-foundation#2655 makes it final, which strands a valid session when the 440 came from our own duplicate socket). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AlmogCohen
added a commit
to AlmogCohen/evolution-api
that referenced
this pull request
Sep 27, 2026
connect(), which both connectToWhatsapp (a new attempt, fresh QR budget) and the backoff reconnect go through, now runs one connect at a time: a connect that arrives while one is under way with the same number joins it and gets the same socket; one for a different number waits for it and then runs. createClient retires the previous socket before building the next: it first detaches Evolution from it (the ev.process subscription and the CB:call listeners), then ends it. The order matters: ending a live Baileys socket emits a close, and if Evolution were still listening that close would reconnect and end the new socket, the recreate loop upstream PR evolution-foundation#2656 has. A new socket also drops any reconnect still waiting on its backoff, since that reconnect was for the socket just replaced; a connect that fails before building one leaves it in place. Events are tied to the socket that emitted them: a batch from a socket that is no longer this.client is dropped, and connectionUpdate ignores a connection.update from a replaced socket even if it was queued before the switch. 440 stays reconnectable (PR evolution-foundation#2655 makes it final, which strands a valid session when the 440 came from our own duplicate socket). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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: