Skip to content

fix(atunnel): end a CONNECT tunnel when the actor closes its connection - #451

Merged
teemow merged 2 commits into
giantswarmfrom
fork/atunnel-tunnel-ends-with-actor
Oct 15, 2026
Merged

teemow merged 2 commits into
giantswarmfrom
fork/atunnel-tunnel-ends-with-actor

Conversation

@teemow

@teemow teemow commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Problem

TestIngressProtocolDowngrade/grpc_to_non-grpc_actor_fails_loudly flaked on the microvm lane of E2E (agentgateway) (#450): the router's access log shows the route resolved in 4 ms and the call then waiting the client's full 30 s on the actor leg, on an actor that had answered /readyz over the same path 10 ms before. So no readiness race and no slow runner.

Root cause

agentgateway reaches the actor through atunnel's CONNECT listener, and for a gRPC call it speaks HTTP/2 inside the tunnel. The counter is an HTTP/1.1-only Go server: it answers the h2 preface with an HTTP/1.1 response and closes. relayIngressWithHalfClose ended a tunnel only when both directions had ended or the request was canceled, so the tunnel outlived the actor's connection for as long as the router held its request stream open. When the actor's answer reaches the router, the router fails the call at once (the usual 10 ms). When it does not, as when the actor's close resets a connection with unread input, the router waits for a SETTINGS frame on a tunnel that never ends, until the client gives up.

Change

The relay closes the downstream as soon as the actor stops sending. This is a backport of the relay change alone from upstream's agent-substrate/substrate#2531 (da35a983, in upstream v0.5.0-alpha4), leaving out its Envoy CONNECT router and log plumbing. The patch leaves the line at the first re-pin onto v0.5.0-alpha4 or later. Its ledger file is fork/atunnel-ends-connect-tunnel-when-actor-closes.md.

Proof

  • TestRelayIngressEndsWhenActorCloses (new): an actor that answers and closes, and one that resets the connection, while the router's request stream stays open. Before the change both cases kept the tunnel open past 5 s; after it, both end at once. The atunnel package passes with -race -count=3, and the relay and CONNECT tests pass with -count=50.
  • The e2e keeps its assertion (HTTP 502 or gRPC Unavailable) and its 30 s client timeout. With the fix, the actor's close ends the tunnel, so that timeout is no longer on the failure path.

Acceptance

  • run-tests, govulncheck and the e2e lanes green on this pull request.

no-upgrade-entry: an internal relay fix in atunnel; nothing an operator configures or does changes on upgrade.

relayIngressWithHalfClose returned only once both directions had ended
or the request was canceled. When the actor ended its connection first,
the tunnel stayed open for as long as the router kept its request stream
open, and the router waited on it until its own timeout.

A gRPC call to an HTTP/1.1-only actor takes that path: the router opens
the tunnel and sends the HTTP/2 preface, the actor answers it with an
HTTP/1.1 response and closes. When that answer reaches the router it
fails the call at once; when it does not, as when the actor's close
resets a connection with unread input, the router waits for the actor's
SETTINGS frame on a tunnel that never ends. The networking e2e's
TestIngressProtocolDowngrade hit it as a 30s client timeout.

The relay now closes the downstream as soon as the actor stops sending,
as upstream's relay does since agent-substrate's CONNECT ingress for
Envoy: a backport of that commit's relay change alone.

Signed-off-by: Timo Derstappen <teemow@gmail.com>
@teemow
teemow requested a review from a team as a code owner October 15, 2026 05:44
Signed-off-by: Timo Derstappen <teemow@gmail.com>
@teemow
teemow merged commit 690228e into giantswarm Oct 15, 2026
21 of 25 checks passed
@teemow
teemow deleted the fork/atunnel-tunnel-ends-with-actor branch October 15, 2026 06:05
teemow added a commit to giantswarm/agent-platform that referenced this pull request Oct 15, 2026
…ix (#1035)

Move components.substrate{,-crds}.versionRange to >=1.11.4 <1.12.0.
atunnel, which runs in the worker's ateom, now ends a CONNECT tunnel once
the actor closes its connection (giantswarm/substrate#451), so a call to
such an actor fails at once instead of waiting out its deadline. The
derived worker image, the customer BOM and the golden render follow; same
upstream pin, no persisted-format change.

Closes #1034

Signed-off-by: Timo Derstappen <teemow@gmail.com>
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.

1 participant