fix(bot): stop reconnect loop during fresh pairing — root cause of QR rotation every 5s
The session-manager's auto-reconnect (5 s after a non-logged-out close) was firing during initial pairing. Baileys closes the socket whenever it exhausts its QR refs (or transient handshake errors); the auto-reconnect then opened a brand-new socket → new QR pool → another close 5 s later. The web saw a fresh QR every ~5 s and the user could never link, because WhatsApp invalidates each QR as soon as Baileys cycles to the next. Fix: only auto-reconnect for accounts that have been linked before (`whatsapp_accounts.last_connected_at IS NOT NULL`). For brand-new pairing attempts the pair-handler's 5-minute window is now the single authority; on close we just stop the session and let the operator retry. With auto-reconnect off, Baileys uses its default QR cadence: 60 s for the first QR, 20 s for each subsequent rotation, ~6 refs total (~3 minutes of valid scanning) — plenty of time to scan. Pair-handler now also surfaces ANY close as `session.timeout` to the web (was only emitting on `loggedOut`). Without this the user would be left staring at the last QR after Baileys gives up, with no way to know pairing failed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7b4f0d0b84
commit
4d10c72551
@ -128,7 +128,12 @@ export async function handleStartPairing(accountId: string): Promise<void> {
|
||||
count: synced,
|
||||
});
|
||||
off();
|
||||
} else if (event.type === "close" && event.loggedOut) {
|
||||
} else if (event.type === "close") {
|
||||
// During the pairing window, ANY close means the QR window
|
||||
// ended without a successful link — Baileys' default is to
|
||||
// close after exhausting QR refs (~2.5 min). Surface this to
|
||||
// the UI so the user gets a "pairing timed out" screen and a
|
||||
// chance to retry, instead of staring at a stale QR forever.
|
||||
const t = pairTimeouts.get(id);
|
||||
if (t) {
|
||||
clearTimeout(t);
|
||||
|
||||
@ -141,15 +141,31 @@ class SessionManager {
|
||||
.set({ status: event.loggedOut ? "logged_out" : "disconnected" })
|
||||
.where(eq(whatsappAccounts.id, accountId));
|
||||
|
||||
if (!event.loggedOut) {
|
||||
if (event.loggedOut) {
|
||||
await this.stop(accountId);
|
||||
} else {
|
||||
// Only auto-reconnect for accounts that have been linked at least
|
||||
// once — `lastConnectedAt` is set on `open`. During an initial
|
||||
// pairing attempt the close event fires every time Baileys
|
||||
// exhausts QR refs (~every 30s). Reconnecting would restart the
|
||||
// pair dance and rotate the QR every few seconds — pair-handler
|
||||
// already manages the pairing window via its own 5-min timeout.
|
||||
const account = await db.query.whatsappAccounts.findFirst({
|
||||
where: (a, { eq }) => eq(a.id, accountId),
|
||||
columns: { lastConnectedAt: true },
|
||||
});
|
||||
if (account?.lastConnectedAt) {
|
||||
const timer = setTimeout(() => {
|
||||
this.reconnectTimers.delete(accountId);
|
||||
void this.stop(accountId).then(() => this.start(accountId));
|
||||
}, 5000);
|
||||
this.reconnectTimers.set(accountId, timer);
|
||||
} else {
|
||||
// Brand-new account that hasn't authenticated yet — let the
|
||||
// pair-handler clean up via its timeout.
|
||||
await this.stop(accountId);
|
||||
}
|
||||
}
|
||||
} else if (event.type === "qr") {
|
||||
await db
|
||||
.update(whatsappAccounts)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user