Skip to content

fix(gateway): add max reconnect limit to scheduleReconnect (#45469)#77556

Closed
stellamariesays wants to merge 3 commits into
openclaw:mainfrom
stellamariesays:fix/max-reconnect-limit
Closed

fix(gateway): add max reconnect limit to scheduleReconnect (#45469)#77556
stellamariesays wants to merge 3 commits into
openclaw:mainfrom
stellamariesays:fix/max-reconnect-limit

Conversation

@stellamariesays

Copy link
Copy Markdown

scheduleReconnect() retried indefinitely with exponential backoff capped at 30s but no maximum retry count. If the gateway is unreachable, the client loops forever accumulating listeners and zombie processes.

Changes:

  • Add MAX_RECONNECT_ATTEMPTS (30) as a static class constant
  • scheduleReconnect() now gives up after 30 failed attempts, fires onReconnectPaused with a descriptive reason, and sets closed = true
  • reconnectAttempts resets to 0 on successful hello handshake
  • reconnectAttempts resets to 0 on explicit stop()
  • Two new tests: max-reconnect-gives-up and counter-resets-on-success

Closes #45469

Summary

Describe the problem and fix in 2–5 bullets:

If this PR fixes a plugin beta-release blocker, title it fix(<plugin-id>): beta blocker - <summary> and link the matching Beta blocker: <plugin-name> - <summary> issue labeled beta-blocker. Contributors cannot label PRs, so the title is the PR-side signal for maintainers and automation.

  • Problem:
  • Why it matters:
  • What changed:
  • What did NOT change (scope boundary):

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

For bug fixes or regressions, explain why this happened, not just what changed. Otherwise write N/A. If the cause is unclear, write Unknown.

  • Root cause:
  • Missing detection / guardrail:
  • Contributing context (if known):

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
  • Scenario the test should lock in:
  • Why this is the smallest reliable guardrail:
  • Existing test that already covers this (if any):
  • If no new test is added, why not:

User-visible / Behavior Changes

List user-visible changes (including defaults/config).
If none, write None.

Diagram (if applicable)

For UI changes or non-trivial logic flows, include a small ASCII diagram reviewers can scan quickly. Otherwise write N/A.

Before:
[user action] -> [old state]

After:
[user action] -> [new state] -> [result]

Security Impact (required)

  • New permissions/capabilities? (Yes/No)
  • Secrets/tokens handling changed? (Yes/No)
  • New/changed network calls? (Yes/No)
  • Command/tool execution surface changed? (Yes/No)
  • Data access scope changed? (Yes/No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS:
  • Runtime/container:
  • Model/provider:
  • Integration/channel (if any):
  • Relevant config (redacted):

Steps

Expected

Actual

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios:
  • Edge cases checked:
  • What you did not verify:

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

  • Backward compatible? (Yes/No)
  • Config/env changes? (Yes/No)
  • Migration needed? (Yes/No)
  • If yes, exact upgrade steps:

Risks and Mitigations

List only real risks for this PR. Add/remove entries as needed. If none, write None.

  • Risk:
    • Mitigation:

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S triage: blank-template Candidate: PR template appears mostly untouched. labels May 4, 2026
@clawsweeper

clawsweeper Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge.

Summary
This PR adds an optional maxReconnectAttempts GatewayClient option, tracks and resets reconnect attempts, pauses reconnect after the opt-in cap, and adds two client tests.

Reproducibility: yes. Source inspection shows current main can keep scheduling ordinary reconnects indefinitely, and the latest PR diff only caps clients that explicitly pass maxReconnectAttempts; no production caller currently does so.

Real behavior proof
Needs real behavior proof before merge: The external PR body has no after-fix terminal output, logs, screenshots, recordings, or linked artifacts showing the changed reconnect behavior in a real setup.

Next step before merge
Contributor action and maintainer policy are both needed: the PR lacks real behavior proof and the production retry policy is not safely inferable for automation.

Security
Cleared: The diff changes in-process reconnect counters/options and tests only; it adds no dependencies, permissions, secret handling, downloads, or code-execution surface.

Review findings

  • [P2] Wire the reconnect limit to a real caller — src/gateway/client.ts:164
Review details

Best possible solution:

Define a caller-aware reconnect policy, wire it to the intended production surface with regression coverage, preserve node-host recovery unless maintainers choose otherwise, and document any new client option or terminal reconnect behavior.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main can keep scheduling ordinary reconnects indefinitely, and the latest PR diff only caps clients that explicitly pass maxReconnectAttempts; no production caller currently does so.

Is this the best way to solve the issue?

No. The opt-in cap avoids the prior node-host regression, but it does not solve the reported production behavior; the narrower maintainable path is an explicit caller-specific policy or threshold callback chosen by maintainers.

Full review comments:

  • [P2] Wire the reconnect limit to a real caller — src/gateway/client.ts:164
    After the latest force-push, maxReconnectAttempts is only an optional GatewayClient option and the only non-test behavior changes when a caller supplies it. All existing production constructors, including node-host, omit it, so merging this would still leave the linked unbounded reconnect path unchanged while closing [Bug P2] scheduleReconnect() has no max retry limit — infinite reconnect loop #45469. Either set a caller-specific policy for the intended surface or keep this as a non-closing preparatory API change.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.88

Acceptance criteria:

  • pnpm test src/gateway/client.test.ts src/gateway/client.watchdog.test.ts
  • pnpm test src/tui/gateway-chat.test.ts src/tui/tui.test.ts
  • pnpm check:changed

What I checked:

  • Current main reconnects ordinary closes without a retry ceiling: The close handler still calls scheduleReconnect() for ordinary closes, and scheduleReconnect() only applies backoff capped at 30 seconds before calling start() again. (src/gateway/client.ts:391, b31774749cc0)
  • Latest PR diff makes the cap opt-in: The latest patch adds maxReconnectAttempts?: number and only stops reconnecting when that option is non-null. (src/gateway/client.ts:160, b3385ff8c15c)
  • Production call sites do not pass the new option: Search found current GatewayClient constructors in node-host, TUI, SDK, ACP, MCP, probes, tests, and extensions, but maxReconnectAttempts is only present in unrelated realtime transcription/SSE clients on current main and in the PR tests. (src/node-host/runner.ts:222, b31774749cc0)
  • Node-host recovery is intentionally unbounded today: runNodeHost comments that connect errors should keep retrying because GatewayClient handles retrying, and its reconnect-paused handler exits only for auth detail codes. (src/node-host/runner.ts:255, b31774749cc0)
  • Protocol docs list backoff but no retry-attempt maximum: The gateway protocol docs document initial reconnect backoff and max reconnect backoff as reference client constants, with no maximum reconnect-attempt limit. Public docs: docs/gateway/protocol.md. (docs/gateway/protocol.md:569, b31774749cc0)
  • Related issue discussion flagged policy ambiguity: A related issue comment notes node clients may intentionally retry forever for gateway recovery and suggests listener cleanup, warning/reset behavior, or an event after N failures instead of a blanket stop.

Likely related people:

  • steipete: Recent commits changed GatewayClient startup/retry handling, stale-token reconnect-loop handling, and node-host gateway restart recovery on the same reconnect surface. (role: recent maintainer and adjacent owner; confidence: high; commits: 4ee537a04ad0, 885806d5ca8d, 8d58ad4c15cd; files: src/gateway/client.ts, src/gateway/client.test.ts, src/node-host/runner.ts)
  • joshavant: Merged history includes shared auth resolution across node-host plus token fallback/reconnect behavior and docs adjacent to the retry-policy decision. (role: recent reconnect/auth maintainer; confidence: medium; commits: a76e81019333, 25252ab5ab15; files: src/gateway/client.ts, src/gateway/client.test.ts, src/node-host/runner.ts)
  • Takhoffman: Adjacent GatewayClient reliability work bounded unanswered client requests and touched the same client/watchdog area related to listener and timeout cleanup. (role: adjacent reliability owner; confidence: medium; commits: 5fc43ff0ecd8; files: src/gateway/client.ts, src/gateway/client.watchdog.test.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against b31774749cc0.

@stellamariesays
stellamariesays force-pushed the fix/max-reconnect-limit branch from 26881f7 to e2c4778 Compare May 4, 2026 22:17
…45469)

scheduleReconnect() retried indefinitely with exponential backoff capped at
30s but no maximum retry count. If the gateway is unreachable, the client
loops forever accumulating listeners and zombie processes.

Changes:
- Add MAX_RECONNECT_ATTEMPTS (30) as a static class constant
- scheduleReconnect() now gives up after 30 failed attempts, fires
  onReconnectPaused with a descriptive reason, and sets closed = true
- reconnectAttempts resets to 0 on successful hello handshake
- reconnectAttempts resets to 0 on explicit stop()
- Two new tests: max-reconnect-gives-up and counter-resets-on-success

Closes openclaw#45469
TypeScript strict null checks require string | null, not undefined.
@stellamariesays
stellamariesays force-pushed the fix/max-reconnect-limit branch from 8913ad3 to 71c3132 Compare May 4, 2026 22:45
Address ClawSweeper review feedback:
- P2: Make reconnect cap opt-in via maxReconnectAttempts option.
  Undefined = unlimited, preserving node-host unbounded retry behavior.
- P3: Fix reset test to send proper type:"res" with payload.type:"hello-ok"
  instead of type:"connect" so handleMessage actually processes it.
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. label May 5, 2026
@stellamariesays

Copy link
Copy Markdown
Author

Closing in favor of a new PR. Fixed review feedback: made reconnect cap opt-in via maxReconnectAttempts option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime size: S triage: blank-template Candidate: PR template appears mostly untouched. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug P2] scheduleReconnect() has no max retry limit — infinite reconnect loop

1 participant