diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index df5e3add5..977d9d3ec 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -264,6 +264,7 @@ export class BaileysStartupService extends ChannelStartupService { private isDeleting = false; // Flag to prevent reconnection during deletion private logBaileys = this.configService.get('LOG').BAILEYS; private eventProcessingQueue: Promise = Promise.resolve(); + private _lastStream515At = 0; // Cumulative history sync counters (reset on new sync or completion) private historySyncMessageCount = 0; @@ -275,6 +276,13 @@ export class BaileysStartupService extends ChannelStartupService { private readonly MESSAGE_CACHE_TTL_SECONDS = 5 * 60; // 5 minutes - avoid duplicate message processing private readonly UPDATE_CACHE_TTL_SECONDS = 30 * 60; // 30 minutes - avoid duplicate status updates + // Reconnect behaviour for the Baileys "stream:error 515" sequence. + // After WhatsApp emits 515 it usually closes with `loggedOut`; that close is *not* a real logout + // and we should reconnect. We treat any close arriving within this grace window as 515-driven. + private static readonly STREAM_515_RECONNECT_GRACE_MS = 30_000; + // The numeric WhatsApp stream-error code that triggers the grace-period reconnect above. + private static readonly STREAM_ERROR_CODE_RECONNECT = '515'; + public stateConnection: wa.StateConnection = { state: 'close' }; public phoneNumber: string; @@ -506,7 +514,12 @@ export class BaileysStartupService extends ChannelStartupService { return; } - const shouldReconnect = !codesToNotReconnect.includes(statusCode); + // If a stream:error 515 (Baileys' "restart needed" handshake) just fired, + // a follow-up loggedOut is the expected restart signal — not an actual + // logout — so reconnect anyway. + const recentStream515 = Date.now() - this._lastStream515At < BaileysStartupService.STREAM_515_RECONNECT_GRACE_MS; + const shouldReconnect = + !codesToNotReconnect.includes(statusCode) || (statusCode === DisconnectReason.loggedOut && recentStream515); this.logger.info({ message: 'Connection closed, evaluating reconnection', @@ -515,6 +528,7 @@ export class BaileysStartupService extends ChannelStartupService { instanceName: this.instance.name, }); + if (shouldReconnect) { // Add 3 second delay before reconnection to prevent rapid reconnection loops this.logger.info('Reconnecting in 3 seconds...'); @@ -813,6 +827,12 @@ export class BaileysStartupService extends ChannelStartupService { this.sendDataWebhook(Events.CALL, payload, true, ['websocket']); }); + this.client.ws.on('CB:stream:error', (node: { attrs?: { code?: string | number } }) => { + if (String(node?.attrs?.code) === BaileysStartupService.STREAM_ERROR_CODE_RECONNECT) { + this._lastStream515At = Date.now(); + } + }); + this.phoneNumber = number; return this.client;