Repository navigation
improvement(interception): keep tunnels serving with prime-tunnel - #3041
Conversation
The watchdog only reads the tunnel service's status, so a tunnel that stays connected without serving is never restarted, and the elastic pool keeps assigning rollouts to it. prime-tunnel 0.1.16 has Tunnel.keep_serving(), which probes a health route through the URL, so the watchdog goes. Interception servers and tool servers both answer the health route. A tunnel that can never work again now retires its server: its rollouts fail with TunnelError and the pools stop choosing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Tunnel recovery now uses end-to-end health checks, and permanently lost interception tunnels retire cleanly instead of accepting more rollouts. Health endpoints expose only a constant response, while replacement and cleanup remain scoped to affected runtime servers. Notes:
You can add or adjust custom eligibility rules. Learn more. |
A retired server kept its listener and client pool until the pool stopped, so tunnel failures in a long run would pile them up. Stop one when the pool next picks a server, once its rollouts have left. A rollout still on it is using its client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit dd2bf28. Configure here.
…cancelled A rollout cancelled while its acquire was stopping a retired server could interrupt the listener cleanup. The server's exit stack is already drained by then, so the pool's own teardown wouldn't close the listener either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
keep_serving now waits 60 s between its two probes, so a short failure of the check on the host doesn't restart a working frpc. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els-serving Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els-serving Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Bravo. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…els-serving Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Problem
A tunnel can look
connectedwhile requests through its URL fail. The current watchdog only checks that status, so it never restarts frpc, and the elastic pool keeps sending new rollouts to the broken server.What this PR changes
_watchis removed.PrimeTunnel.exposenow runsTunnel.keep_serving()from prime-tunnel 0.1.17, which restarts frpc under the same URL when the URL fails but the local service still answers.GET /vf/healthwithok, without auth.keep_servingprobes this route.TunnelErrorand it refuses new ones. The elastic pool starts a replacement and stops the old server once its rollouts have left. A static pool uses its remaining servers, and fails the rollout if none are left.TunnelLogHandlernow listens toprime_tunnelinstead ofprime_tunnel.frpc.Behaviour to review
keep_servingrestarts frpc if the URL check fails twice, 60 s apart, while the local service answers. That drops requests in flight, even if the failure is only on the host's path to the URL.Note
Medium Risk
Changes remote-eval critical path (tunnel keepalive, server retirement, and pool routing); mis-handled tunnel loss or aggressive frpc restarts could fail or disrupt in-flight rollouts.
Overview
Replaces the in-process tunnel watchdog (periodic
status()checks and manual frpc restarts) with prime-tunnel 0.1.17’skeep_serving(HEALTH_PATH), so liveness is judged by whether requests through the public URL reach the local service. Minimum dependency is bumped toprime-tunnel>=0.1.17.Interception and MCP servers now expose unauthenticated
GET /vf/health(HEALTH_PATH) returningokfor those probes.PrimeTunnelwiresTunnel.on_gonewhen registration is permanently lost;InterceptionServermarks itself unhealthy, sets active rollouts’TunnelError, releases sessions, and blocks new registrations. Pools skip unhealthy servers—elastic spins up replacements and shielded_free_retiredstops old listeners once load is zero; static raisesTunnelErrorwhen every server’s tunnel is gone. Tunnel SDK logs are forwarded from theprime_tunnellogger.Unit tests drop the old watchdog matrix and add coverage for keep-serving lifecycle, gone callbacks, the health route, and pool retirement.
Reviewed by Cursor Bugbot for commit b60e598. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Keep prime tunnels serving via SDK
keep_servingand fail rollouts on tunnel lossPrimeTunnel.exposewith the prime-tunnel SDK'skeep_servingusingHEALTH_PATH; permanent loss (TunnelGoneError) fires the newon_gonecallback. Cleanup cancels the monitor task and stops the client via a worker thread. Bumps prime-tunnel minimum to 0.1.17 (pyproject.toml)InterceptionServernow starts healthy, serves anokhealth route atHEALTH_PATH, and on tunnel loss marks itself unhealthy, fails registered sessions withTunnelError, and refuses new registrations (server.py)StaticInterceptionPool.acquireselects only healthy servers and raisesTunnelErrorwhen none exist;ElasticInterceptionPoolstops and removes retired zero-load servers, and skips unhealthy or full servers when creating new ones (pool.py)prime_tunnellogger and strips a leading "Tunnel " prefix (prime.py). The MCP server also serves the health route (server.py)StaticInterceptionPool.acquirenow raisesTunnelErrorwhere it previously could return an unhealthy server; the removed_keep_servingrestart loop means tunnels are no longer restarted in-processChanges since #3041 opened
HEALTH_PATHconstant in theverifiers.v1.interception.tunnel.basemodule from/__verifiers/healthzto/vf/health. [c81e4f0]Macroscope summarized b60e598.