fix(whatsapp): exponential reconnect backoff to prevent 405 spam loop - #119
Conversation
The bridge retried every non-logout socket close at a flat 3s forever. A stale-protocol-version 405 rejection produced 11,708 consecutive reconnects (~1200 req/hr) on prod, the traffic pattern that risks a WhatsApp account ban. Non-515 closes now use exponential backoff + jitter capped at 5 min; the 515 post-pairing fast path (1s) is preserved and the attempt counter resets on a successful connection open. Patch note: ~/.hermes/plans/hermes-patches/whatsapp-bridge-reconnect-backoff.md
|
Claude finished @exiao's task in 1m 27s —— View job Review: PR #119 — WhatsApp reconnect backoff
LGTM. The final
Tests are invariant/behavior-based (relate reason+attempt → delay class) rather than snapshots — good. Traced all six This is a standalone Baileys bridge subprocess, so the agent-core invariants (prompt-cache stability, role alternation, narrow-waist tools, Minor (non-blocking):
Could not run 0 blocking, 2 minor. |
There was a problem hiding this comment.
LGTM — exponential backoff + jitter math is correct (3s·2^(n-1), capped at 5min), counter resets on both connection === 'open' and the 515 fast path, and jitter breaks the bot-like fixed cadence. Standalone Baileys bridge process, so agent-core invariants (prompt-cache, role alternation, narrow-waist tools) don't apply; no config.yaml/env changes. Non-blocking note: the 515 path stays flat 1s with the counter reset (matches original intent, out of scope). 0 blocking.
There was a problem hiding this comment.
Code Review
This pull request introduces exponential backoff with jitter for WhatsApp socket reconnection attempts to prevent hammering servers during persistent failures. The review feedback suggests capping the exponent in the backoff calculation to prevent potential arithmetic overflow when the number of reconnection attempts becomes very large.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Spread each reconnect uniformly over 0..backoff instead of a fixed +0-1s, so retries never settle into a regular machine cadence a bot-detector could flag.
Replace the exponential backoff with a fresh uniform-random pick in [3min,30min] on every non-515 reconnect. Deliberately non-monotonic (e.g. 3m,15m,4m,30m) so the cadence looks nothing like a machine, per Eric's request. Drops a persistent failure from ~1200 retries/hr to ~2/hr.
There was a problem hiding this comment.
LGTM — exponential backoff + jitter math is correct, counter resets on both the 515 fast path and connection === 'open', and Gemini's overflow note is a non-bug in practice (Math.min caps backoff to 300000 before it feeds Math.random, so no Infinity/NaN). Standalone Baileys bridge process, so agent-core invariants don't apply. One minor doc-only note: the 'full jitter (0..backoff)' comment overstates the code, which is actually 3000 + rand(0..backoff). 0 blocking, 1 minor.
Count consecutive non-515 reconnect failures; the first 10 use the random 3-30min delay, and attempt 11+ waits a full 12h each cycle. A successful connect resets the counter. Stops a persistent failure (stale client / banned handshake) from retrying indefinitely and risking the account.
There was a problem hiding this comment.
LGTM — no blocking issues. Uniform-random 3-30min reconnect delay math is correct and the 515 fast path is intact. Two minor notes (posted in detail on the PR comment): (1) the block comment at bridge.js:438-441 still says 'exponential backoff + jitter' but the code now does a flat uniform-random pick — stale doc; (2) the 3-min floor applies to all transient drops, so ordinary network blips now incur a 3-30min outage instead of ~3s — intentional anti-ban tradeoff, flagging for awareness. Standalone Baileys bridge, no agent-core/config impact.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9179e7ed64
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
LGTM — reviewed the current reconnect logic in scripts/whatsapp-bridge/bridge.js:440-473. Uniform-random [3min,30min] backoff + 12h hard backoff after 10 failures correctly breaks the 405 spam loop; counter resets on connection open and the 515 fast path is intact. Standalone Baileys subprocess, no agent-core/config/env impact. 3 minor non-blocking notes posted on the PR comment (3-min floor now hits benign transient drops; stale 'exponential' comment; cosmetic off-by-one in the give-up log). 0 blocking.
There was a problem hiding this comment.
LGTM — reconnectPlan refactor resolves all prior blocking concerns: 515 resets the counter, first non-515 retry is a flat 3s, exponent is capped so no overflow. Capped exponential jitter [3s,5min] → hard 12h backoff on the 11th failure; connection=open resets. Standalone Baileys subprocess, no agent-core/config/env impact. 2 minor non-blocking notes on the PR comment (duplicated RECONNECT_GIVEUP_AFTER constant; ~21min-to-12h-backoff window affects benign long outages). 0 blocking.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1f994a60d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
LGTM — traced reconnectPlan against all five native-test cases: 515 resets the counter, first non-515 retry is a flat 3s, repeated failures use capped exponential jitter [3s,5min] (exponent capped, no overflow), and the 12h hard backoff is now scoped to persistent 405 handshake rejections only. Resolves every prior review thread. 2 minor non-blocking notes on the PR comment (duplicated RECONNECT_GIVEUP_AFTER constant; non-405 persistent failures retry at the 5min cap indefinitely). Standalone Baileys subprocess — no agent-core/config/env impact.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2864bafc3a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
LGTM — traced reconnectPlan against all native test cases. The latest commit (track handshake failure streaks) resolves the last Codex thread: handshakeFailures is now a 405-specific streak counter, separate from reconnectAttempts, so mixed transient+405 failures no longer trigger the 12h backoff early. Policy is correct: 515 fast path resets counters, first non-515 retry is flat 3s, repeated failures use capped exponential jitter [3s,5min] (exponent capped, no overflow), 11th consecutive 405 enters 12h hard backoff, connection=open resets. Standalone Baileys subprocess — no agent-core/config/env impact. 0 blocking, 2 minor (duplicated RECONNECT_GIVEUP_AFTER constant; non-405 persistent failures retry at 5min cap indefinitely by design).
There was a problem hiding this comment.
LGTM — reconnectPlan is correct: 515 resets both counters (flat 1s), first non-515 retry is flat 3s, repeated failures use capped exponential jitter in [3s,5min] (exponent capped, no overflow), and the 12h hard backoff is scoped to the 11th consecutive 405 via a 405-only handshakeFailures streak. connection=open resets both counters. Tests are invariant-based and cover all cases including mixed transient+405. Standalone Baileys subprocess — no agent-core/config/env impact. Minor: RECONNECT_GIVEUP_AFTER is duplicated across bridge.js and bridge_helpers.js (agree at 10 today). 0 blocking, 2 minor.
Problem
The Baileys WhatsApp bridge retried every non-logout socket close at a flat 3s forever. When WhatsApp rejects the handshake with reason
405(stale/outdated client protocol version), the socket closes and reconnects on a 3s loop with no ceiling.Hit live on the BloomBot prod VPS: a stale hardcoded protocol version produced 11,708 consecutive 405 reconnects (~1,200 req/hr to WhatsApp's socket endpoint) — exactly the traffic pattern that gets a WhatsApp account flagged/banned as an abusive client.
Fix
Replace the flat
reason === 515 ? 1000 : 3000reconnect delay:min(3000 * 2^(n-1), 300000) + rand(0..1000)ms, capped at 5 min. Worst case: ~1 req/3s → ~1 req/5min.reconnectAttempts = 0on successfulconnection === 'open'.Why this PR
The fix was applied live on prod to stop the ban risk immediately, but a live edit is wiped by the next runtime
git pull— the committed base still has the flat-3s loop. Without this PR the bug resurrects on the next deploy.Verification
node --check scripts/whatsapp-bridge/bridge.js→ syntax OK/health=connected, fresh log ends at✅ WhatsApp connected!with 0 new 405s after QR scan.Patch note:
~/.hermes/plans/hermes-patches/whatsapp-bridge-reconnect-backoff.md