Skip to content

Give route-backed containers the full pinned dial budget and retry - #1848

Merged
luke-lombardi merged 2 commits into
mainfrom
ll/route-dial-parity
Aug 16, 2026
Merged

Give route-backed containers the full pinned dial budget and retry#1848
luke-lombardi merged 2 commits into
mainfrom
ll/route-dial-parity

Conversation

@luke-lombardi

@luke-lombardi luke-lombardi commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Root cause (measured in production)

The CNN sandbox burst failures (20% 502s at ~1.15s, throughput collapse to ~9 req/s) trace to the pinned-container path in the pod proxy. Every sandbox on a rented machine is addressed as route://…, and that path got a 900ms dial budget with no retry, while direct addresses got 3s + one retry.

Evidence from gateway metrics for the affected stub:

  • Successful tunnel dials: 100–190ms average. Failed dials: 1.12s average — i.e. the 900ms budget plus overhead. Half of all dials during bursts failed.
  • Background discovery dials to the same machine fail ~40–50% continuously at a ~2s cap, so the tunnel is slow at connection setup even unloaded (raw internet RTT to the machine is 38ms; the tunnel round trip is ~160ms — relayed path).
  • Observed collapse throughput of 8.9 req/s matches 16 global dial slots draining at ~1s effective dial time; the backend app itself serves 612 req/s in-container.

Fix

  • Route-backed pinned requests get the same treatment as direct: 3s dial budget, one pre-connect retry, pinning. (containerPinnedRouteDialTimeout removed.)
  • backendRouteDialConcurrency raised 16 → 64 so one slow machine cannot serialize dials for the whole gateway.
  • A stuck-opening route now 502s after the budget plus one retry (~6s) instead of 0.9s; test updated to lock in that bound.

Test plan

  • go test ./pkg/abstractions/pod/ ./pkg/network/ passes
  • Post-deploy: re-run in-cluster burst (c=32) against a route-backed sandbox — expect 0% 502s

Made with Cursor


Summary by cubic

Route-backed container dials now get the same pinned budget and retry as direct addresses, and embedded tailscale is bumped to v1.102.2 to restore direct paths and reduce relay-only flakiness. Old: route:// used a 900ms dial with no retry and older tailscale often stuck on DERP relays. New: 3s dial with one pre-connect retry and pinning; tailscale negotiates direct connections and guards tsnet.Server.Close; stuck-opening routes now fail in ~6s instead of ~0.9s.

Review and rollout

  • Unify pinned dial handling in pkg/abstractions/pod/proxy.go: always use containerPinnedDialTimeout (3s), enable retry, pin; remove containerPinnedRouteDialTimeout.
  • Raise route dial concurrency 16 → 64 in pkg/network/backend_dialer.go.
  • Upgrade tailscale to v1.102.2; add closeTSNetServer and use it in pkg/network/tailscale.go to tolerate tsnet.Server.Close panics on wedged servers.
  • Update test to bound stuck-opening routes at ~2*3s + 1s and expect 502.
  • Migration: build with Go 1.26+; monitor max request latency for route-open failures and gateway dial failure rates post-deploy.

Written for commit 06e351e. Summary will update on new commits.

Review in cubic

Pinned requests to route:// containers (every sandbox on a rented
machine) were capped at a 900ms dial with no retry, while direct
addresses got 3s plus one retry. Production metrics show healthy tunnel
dials take 100-190ms and exceed 900ms under mild concurrency, so bursts
turned into 502s at ~1.15s. Routes now get the same 3s budget, retry,
and pinning, and the global route dial semaphore grows from 16 to 64 so
one slow machine cannot serialize the whole gateway.

Co-authored-by: Cursor <cursoragent@cursor.com>
@luke-lombardi
luke-lombardi requested a review from mernit August 16, 2026 16:15
The v1.72.1 tsnet embedded in the agent stops sending disco pings under
symmetric NAT, pinning gateway-to-agent traffic on DERP relays (~140ms
dials, intermittent failures). v1.102.2 negotiates direct paths again.
Guard tsnet.Server.Close during recycling, which the newer library
panics on for servers that never finished initializing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@luke-lombardi
luke-lombardi merged commit d00b769 into main Aug 16, 2026
4 checks passed
@luke-lombardi
luke-lombardi deleted the ll/route-dial-parity branch August 16, 2026 16:43
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