diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index eb5a488b..d22b159f 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -996,12 +996,27 @@ export const makeSocket = (config: SocketConfig) => { } catch {} } + // Detect socket-level session errors that require recreation + const statusCode = (error as Boom)?.output?.statusCode || 0 + const isSessionError = ( + statusCode === DisconnectReason.badSession || + statusCode === DisconnectReason.restartRequired + ) + + if (isSessionError) { + logger.warn( + { statusCode, reason: DisconnectReason[statusCode] }, + '🔴 Socket-level session error - consumer should recreate socket' + ) + } + ev.emit('connection.update', { connection: 'close', lastDisconnect: { error, date: new Date() - } + }, + isSessionError }) ev.removeAllListeners('connection.update') } @@ -1404,27 +1419,6 @@ export const makeSocket = (config: SocketConfig) => { // update credentials when required ev.on('creds.update', async update => { - // CRITICAL: Handle session errors by emitting close event for consumer-level reconnect - if (update.error) { - logger.error({ error: update.error }, '🔴 Session error detected') - - // Session errors indicate keys are desynchronized - socket must be recreated - // Emit close event so consumer can call makeWASocket() again - ev.emit('connection.update', { - connection: 'close', - lastDisconnect: { - error: update.error, - date: new Date() - }, - // Include session error flag for consumer to detect - isSessionError: true - }) - - // Cleanup current socket - await end(update.error) - return - } - const name = update.me?.name // if name has just been received if (creds.me?.name !== name) { diff --git a/src/Utils/structured-logger.ts b/src/Utils/structured-logger.ts index 04d3ceaf..6ebb997b 100644 --- a/src/Utils/structured-logger.ts +++ b/src/Utils/structured-logger.ts @@ -411,6 +411,8 @@ export class StructuredLogger implements ILogger { // Metrics module (lazy loaded) private metricsModule: typeof import('./prometheus-metrics') | null = null private metricsQueue: Array<() => void> = [] + private metricsImportFailed = false + private readonly MAX_METRICS_QUEUE_SIZE = 1000 constructor(config: StructuredLoggerConfig) { const envConfig = loadLoggerConfig() @@ -489,7 +491,9 @@ export class StructuredLogger implements ILogger { this.metricsQueue.forEach(fn => fn()) this.metricsQueue = [] }).catch(() => { - // Metrics not available + // Metrics not available - set flag and clear queue + this.metricsImportFailed = true + this.metricsQueue = [] }) } } @@ -896,6 +900,7 @@ export class StructuredLogger implements ILogger { this.rateLimiter = null this.circuitBreaker = null this.metricsModule = null + this.metricsQueue = [] } }