fix: clear stale routingInfo on restart to prevent slow/unstable connections
fix: clear stale routingInfo on restart to prevent slow/unstable connections
This commit is contained in:
+23
-7
@@ -182,9 +182,13 @@ export const makeSocket = (config: SocketConfig) => {
|
|||||||
// assigns a fresh edge server on this connection. This fixes sessions that became slow
|
// assigns a fresh edge server on this connection. This fixes sessions that became slow
|
||||||
// after a pm2 restart because the previous edge server retained stale state.
|
// after a pm2 restart because the previous edge server retained stale state.
|
||||||
// Signal keys and auth credentials are NOT affected — no QR re-scan is needed.
|
// Signal keys and auth credentials are NOT affected — no QR re-scan is needed.
|
||||||
|
// hadStaleRoutingInfo is used below to skip the offline buffer on reconnect scenarios
|
||||||
|
// (same channel, new QR scan) so live messages are not held hostage by the backlog buffer.
|
||||||
|
let hadStaleRoutingInfo = false
|
||||||
if (config.clearRoutingInfoOnStart && authState?.creds?.routingInfo) {
|
if (config.clearRoutingInfoOnStart && authState?.creds?.routingInfo) {
|
||||||
logger.info('clearRoutingInfoOnStart: discarding stored routingInfo to force fresh edge server assignment')
|
logger.info('clearRoutingInfoOnStart: discarding stored routingInfo to force fresh edge server assignment')
|
||||||
authState.creds.routingInfo = undefined
|
authState.creds.routingInfo = undefined
|
||||||
|
hadStaleRoutingInfo = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
|
if (url.protocol === 'wss' && authState?.creds?.routingInfo) {
|
||||||
@@ -1558,11 +1562,11 @@ export const makeSocket = (config: SocketConfig) => {
|
|||||||
const [reasonNode] = getAllBinaryNodeChildren(node)
|
const [reasonNode] = getAllBinaryNodeChildren(node)
|
||||||
const { reason, statusCode } = getErrorCodeFromStreamError(node)
|
const { reason, statusCode } = getErrorCodeFromStreamError(node)
|
||||||
|
|
||||||
if(reason === 'device_removed') {
|
if (reason === 'device_removed') {
|
||||||
logger.error({ node }, 'stream error: device removed — logging out')
|
logger.error({ node }, 'stream error: device removed — logging out')
|
||||||
} else if(reason === 'xml-not-well-formed') {
|
} else if (reason === 'xml-not-well-formed') {
|
||||||
logger.warn({ node }, 'stream error: sent malformed stanza (xml-not-well-formed)')
|
logger.warn({ node }, 'stream error: sent malformed stanza (xml-not-well-formed)')
|
||||||
} else if(reason === 'ack') {
|
} else if (reason === 'ack') {
|
||||||
logger.warn({ ackId: reasonNode?.attrs?.id, node }, 'stream error: ack-based error')
|
logger.warn({ ackId: reasonNode?.attrs?.id, node }, 'stream error: ack-based error')
|
||||||
} else {
|
} else {
|
||||||
logger.error({ reason, statusCode, node }, 'stream errored out')
|
logger.error({ reason, statusCode, node }, 'stream errored out')
|
||||||
@@ -1611,13 +1615,18 @@ export const makeSocket = (config: SocketConfig) => {
|
|||||||
// Prometheus / history consolidation) and is typically set to 5-30 s by operators.
|
// Prometheus / history consolidation) and is typically set to 5-30 s by operators.
|
||||||
// This constant must remain short regardless so that a large offline backlog cannot
|
// This constant must remain short regardless so that a large offline backlog cannot
|
||||||
// hold live incoming messages hostage for minutes.
|
// hold live incoming messages hostage for minutes.
|
||||||
const OFFLINE_BUFFER_TIMEOUT_MS = 5_000
|
// When clearRoutingInfoOnStart cleared a stale routingInfo, this is a reconnect of an
|
||||||
|
// existing session (same channel, new QR scan after disconnect). In this case we skip
|
||||||
|
// the offline buffer entirely so live messages are not held hostage waiting for the
|
||||||
|
// server to finish flushing the pending-message backlog (CB:ib,,offline).
|
||||||
|
// For normal restarts (no stale routingInfo) the standard 5 s safety cap applies.
|
||||||
|
const OFFLINE_BUFFER_TIMEOUT_MS = hadStaleRoutingInfo ? 0 : 5_000
|
||||||
let offlineBufferTimeout: NodeJS.Timeout | undefined
|
let offlineBufferTimeout: NodeJS.Timeout | undefined
|
||||||
|
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
if (creds.me?.id) {
|
if (creds.me?.id && !hadStaleRoutingInfo) {
|
||||||
// start buffering important events
|
// start buffering important events
|
||||||
// if we're logged in
|
// if we're logged in (and this is not a reconnect-after-stale-routing)
|
||||||
ev.buffer()
|
ev.buffer()
|
||||||
didStartBuffer = true
|
didStartBuffer = true
|
||||||
|
|
||||||
@@ -1626,11 +1635,18 @@ export const makeSocket = (config: SocketConfig) => {
|
|||||||
offlineBufferTimeout = setTimeout(() => {
|
offlineBufferTimeout = setTimeout(() => {
|
||||||
offlineBufferTimeout = undefined
|
offlineBufferTimeout = undefined
|
||||||
if (didStartBuffer) {
|
if (didStartBuffer) {
|
||||||
logger.warn({ timeoutMs: OFFLINE_BUFFER_TIMEOUT_MS }, 'perf: offline-buffer safety timeout reached, force-flushing before CB:ib,,offline')
|
logger.warn(
|
||||||
|
{ timeoutMs: OFFLINE_BUFFER_TIMEOUT_MS },
|
||||||
|
'perf: offline-buffer safety timeout reached, force-flushing before CB:ib,,offline'
|
||||||
|
)
|
||||||
ev.flush()
|
ev.flush()
|
||||||
didStartBuffer = false
|
didStartBuffer = false
|
||||||
}
|
}
|
||||||
}, OFFLINE_BUFFER_TIMEOUT_MS)
|
}, OFFLINE_BUFFER_TIMEOUT_MS)
|
||||||
|
} else if (creds.me?.id && hadStaleRoutingInfo) {
|
||||||
|
logger.info(
|
||||||
|
'clearRoutingInfoOnStart: skipping offline buffer — reconnect scenario, messages will be delivered immediately'
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined })
|
ev.emit('connection.update', { connection: 'connecting', receivedPendingNotifications: false, qr: undefined })
|
||||||
|
|||||||
Reference in New Issue
Block a user