Skip to content

Add exponential backoff on all mesh agent control-channel retry paths - #74

Merged
mikhailm-coder merged 2 commits into
masterfrom
hotfix/mesh-exponential-backoff
Jul 29, 2026
Merged

Add exponential backoff on all mesh agent control-channel retry paths#74
mikhailm-coder merged 2 commits into
masterfrom
hotfix/mesh-exponential-backoff

Conversation

@mikhailm-coder

@mikhailm-coder mikhailm-coder commented Jul 29, 2026

Copy link
Copy Markdown

Summary

Implements 86ajmt7ty: the mesh agent must back off exponentially on all server-communication retry paths and never flood the server with rapid retries.

The existing backoff in MeshServer_Connect (jittered doubling) already covered pre-upgrade failures (DNS, TCP, TLS, non-101 responses), but two paths defeated it:

  1. Zero-delay reconnect flood: MeshServer_SendAgentInfo reset retryTime = 0 mid-handshake, before the server confirmed agent auth. A server that completes the WebSocket upgrade but errors/closes before AuthConfirm caused an immediate-reconnect loop bounded only by TCP+TLS handshake speed.
  2. Dial-timeout bypass: the 20s dial timeout re-dialed via MeshServer_ConnectEx directly, overriding the backoff delay its own cancel path had just scheduled — a fixed 20s loop against a hung/blackholed server.

Changes

  • Reset backoff only after an authenticated session survives 60s (MESH_BACKOFF_STABLE_SESSION_MS); shorter post-auth sessions halve retryTime (floor ~2s) so a flapping-but-working server still recovers quickly while an auth-then-die crash loop stays paced. authTick is stamped in MeshServer_ServerAuthenticated (single choke point covering both auth-completion orders).
  • MeshServer_ConnectEx_NetworkError now falls back to MeshServer_Connect; a new retryTimerPending flag coalesces scheduling so each failure cycle grows the delay exactly once. The flag is cleared at the top of MeshServer_ConnectEx before the re-entry guard (ordering is load-bearing: a guard-blocked stale timer must not strand the flag) and on connection establishment.
  • Connection establishment drops stale agent-keyed retry/lockout timers (ILibLifeTime_AddEx dedupes by key, so duplicate timers are structurally impossible).
  • Backoff cap raised from 4–6 min to jittered 8–10 min.

Verification

  • macOS ARM64 debug build clean; no new -Wall warnings (verified via syntax-only compile of the committed file).
  • Two independent adversarial reviews (design + implementation): flag/timer state machine verified strand-proof across all call sites and interleavings on the chain thread; ILibWebClient_CancelRequest confirmed to synchronously fire OnResponse(header=NULL) on the chain thread, making the NetworkError fallback a coalesced no-op in the normal case; no watchdog depends on the previous ~6 min cap (service auto-restart disabled in 7f2ad09).

Known-accepted (out of scope): IP-change handler still resets backoff to 3s (event-driven, bounded); pre-existing dormancy on ServerID/MeshID config errors; multi-server failover now waits the backoff delay instead of 20s (single-URL configs unaffected).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved reconnect behavior after temporary network interruptions.
    • Prevented duplicate retry scheduling and cleared stale retry state when connections are restored.
    • Added stability-aware backoff handling so brief sessions recover more gradually while longer authenticated sessions reset normally.
    • Increased the maximum retry delay window to reduce repeated rapid connection attempts.

- Reset backoff only after a 60s-stable authenticated session (halve it
  on shorter ones) instead of mid-handshake, closing the zero-delay
  reconnect flood when the server upgrades but errors before AuthConfirm
- Route the 20s dial-timeout fallback through MeshServer_Connect and
  coalesce scheduling via retryTimerPending so each cycle grows the
  delay exactly once
- Drop stale agent-keyed retry/lockout timers on connection establishment
- Raise the backoff cap from 4-6 to 8-10 minutes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@mikhailm-coder, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8fddd513-9848-4893-a5d1-25a4db43b45a

📥 Commits

Reviewing files that changed from the base of the PR and between 87d0a45 and ada2099.

📒 Files selected for processing (1)
  • meshcore/agentcore.c
📝 Walkthrough

Walkthrough

The reconnect logic now tracks authenticated session duration, applies partial or full backoff resets on disconnect, and coalesces pending retry timers across connection paths.

Changes

Reconnect stability and retry scheduling

Layer / File(s) Summary
Authenticated session state
meshcore/agentcore.h, meshcore/agentcore.c
MeshAgentHostContainer documents retry state and adds authTick, which is recorded after full server authentication.
Stable-session backoff policy
meshcore/agentcore.c
Disconnect handling fully resets retry time after stable sessions, otherwise halves it within the minimum bound; an unconditional agent-info reset is removed.
Retry timer coordination
meshcore/agentcore.c
Control-channel recovery clears stale retry state, pending timers are coalesced, retry delay caps increase, and network-timeout recovery uses MeshServer_Connect.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

  • flamingo-stack/meshagent#58: Both changes coordinate MeshServer_ConnectEx retry scheduling to prevent overlapping connection attempts.

Suggested reviewers: denys-gif

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: exponential backoff across mesh agent control-channel retry paths.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/mesh-exponential-backoff

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
meshcore/agentcore.c (1)

5027-5034: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Clamp the computed retry delay to the 8–10 minute cap.

The cap is selected from the current retryTime before jitter is added. For example, retryTime == 479999 can produce a delay of nearly 960 seconds, exceeding the documented 8–10 minute maximum.

Proposed adjustment
 		else
 		{
 			delay = agent->retryTime + (timeout % agent->retryTime);
+			if (delay >= 480000) { delay = 480000 + (timeout % 120000); }
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@meshcore/agentcore.c` around lines 5027 - 5034, Clamp the final computed
delay in the retry logic after jitter is added so it never exceeds the
documented 8–10 minute cap. Update the branch around agent->retryTime and the
delay calculation to apply the cap to the resulting value, including retryTime
values just below 480000, while preserving the existing jitter behavior within
the valid range.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@meshcore/agentcore.c`:
- Around line 4231-4234: Update the short-session branch near agent->authTick so
halving agent->retryTime never produces a value below MESH_BACKOFF_MIN_RETRY_MS,
while still reducing eligible retry times such as 3 seconds. Preserve the
stable-session reset behavior and clear agent->authTick afterward.

---

Outside diff comments:
In `@meshcore/agentcore.c`:
- Around line 5027-5034: Clamp the final computed delay in the retry logic after
jitter is added so it never exceeds the documented 8–10 minute cap. Update the
branch around agent->retryTime and the delay calculation to apply the cap to the
resulting value, including retryTime values just below 480000, while preserving
the existing jitter behavior within the valid range.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 09291a3f-a938-47a5-9866-dc2602f8cbf4

📥 Commits

Reviewing files that changed from the base of the PR and between 47f45f8 and 87d0a45.

📒 Files selected for processing (2)
  • meshcore/agentcore.c
  • meshcore/agentcore.h

Comment thread meshcore/agentcore.c Outdated
… cap

Addresses CodeRabbit review: short-lived authenticated sessions now
always land retryTime in [2s floor, half of previous], and the jittered
doubling can no longer overshoot the 8-10 minute cap to ~16 minutes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mikhailm-coder

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@mikhailm-coder
mikhailm-coder merged commit 9918480 into master Jul 29, 2026
4 checks passed
@mikhailm-coder
mikhailm-coder deleted the hotfix/mesh-exponential-backoff branch July 29, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants