Skip to content

fix(extension-server): deterministic tunnel-offline 503 on the user path for offline connectors#207

Merged
scotwells merged 3 commits into
mainfrom
fix/connector-offline-user-path
Jun 19, 2026
Merged

fix(extension-server): deterministic tunnel-offline 503 on the user path for offline connectors#207
scotwells merged 3 commits into
mainfrom
fix/connector-offline-user-path

Conversation

@scotwells

@scotwells scotwells commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

What a visitor experiences

A visitor reaching a proxy whose Connector is offline gets a generic routed-to-nothing 503 no_healthy_upstream — Envoy's "I had nowhere to send this" — instead of a deliberate tunnel-offline response.

Why: when a Connector is offline, NSO still emits its backendRef, so Envoy Gateway programs a backend cluster with zero endpoints. The ext-server's offline handling only added a route for CONNECT (tunnel-control) clients, so a normal browser GET fell through to the catch-all / route, hit that empty cluster, and produced the generic 503 plus empty-cluster side effects (upstream-health flags, retries, cluster-stat noise).

This makes the offline experience intentional: user traffic returns a deterministic tunnel-offline 503 and never reaches an endpoint-less cluster.

What changed

  • In the offline branch of ApplyConnectorRoutes, user-facing forwarding route(s) targeting the offline connector cluster are rewritten to a direct_response 503 ("Tunnel not online") instead of routing to the empty cluster.
  • The existing connect_matcher offline route is still prepended for CONNECT clients.
  • Only each route's action is replaced — match, metadata, and typed_per_filter_config are preserved.
  • Adds a counter (nso_extension_connector_offline_routes_total) and a connector_offline_routes field on the PostTranslateModify log line.

Notes

  • Online connectors are unchanged — they still get the CONNECT tunnel cluster.
  • Idempotent: a converted route is a direct_response, so re-running never double-applies.

Related

Validation

gofmt clean · go build ./... · go vet ./internal/extensionserver/... · go test ./internal/extensionserver/... all pass. golangci-lint could not run (installed binary built with go1.25; project targets go1.26.4).

🤖 Generated with Claude Code

@scotwells scotwells changed the title fix(extension-server): tunnel-offline 503 on user path for offline connector (Gap B) fix(extension-server): tunnel-offline 503 on user path for offline connector Jun 19, 2026
@scotwells scotwells changed the title fix(extension-server): tunnel-offline 503 on user path for offline connector fix(extension-server): deterministic tunnel-offline 503 on the user path for offline connectors Jun 19, 2026
scotwells and others added 3 commits June 19, 2026 10:30
…line connector

When a Connector is offline, NSO still emits its backendRef, so Envoy
Gateway programs an endpoint-less cluster for the connector backend. The
ext-server's offline handling only prepended a connect_matcher route
(503 "Tunnel not online"), which matches CONNECT (tunnel-control) clients
only. A normal user GET fell through to the prefix:"/" route, still
targeting the zero-endpoint cluster, so Envoy returned a generic 503
no_healthy_upstream (UH) plus retry/cluster-stat noise instead of a
deterministic tunnel-offline response.

ApplyConnectorRoutes now, in the offline branch, also rewrites the
user-facing forwarding route(s) that target the offline connector cluster
into an immediate direct_response 503, reusing the same "Tunnel not
online" body. Only the route's Action oneof is replaced, so each route's
match, metadata, and typed_per_filter_config are preserved. The existing
connect_matcher offline route is still prepended for CONNECT clients. The
online (replaced) path is unchanged.

Idempotent: converted routes become direct_responses, so routeCluster
returns "" for them and they never re-match the connector cluster.

Surfaces a new counter (nso_extension_connector_offline_routes_total) and
a "connector_offline_routes" field on the PostTranslateModify log line.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove step-by-step narration; keep the higher-level rationale (route to a
deterministic 503 instead of an endpoint-less cluster, action-only replace
preserves match/metadata, idempotent because direct_responses carry no cluster).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@scotwells scotwells force-pushed the fix/connector-offline-user-path branch from dbf8854 to cf70fa4 Compare June 19, 2026 15:31
@scotwells scotwells marked this pull request as ready for review June 19, 2026 15:37
@scotwells scotwells merged commit 6ca76df into main Jun 19, 2026
11 checks passed
@scotwells scotwells deleted the fix/connector-offline-user-path branch June 19, 2026 15: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