Skip to content

fix(extproc): don't serve before the first filter config is loaded - #2992

Open
abdulaziz-dev-lab wants to merge 1 commit into
theagentrouter:mainfrom
abdulaziz-dev-lab:fix/extproc-serve-after-first-config-load
Open

abdulaziz-dev-lab wants to merge 1 commit into
theagentrouter:mainfrom
abdulaziz-dev-lab:fix/extproc-serve-after-first-config-load

Conversation

@abdulaziz-dev-lab

Copy link
Copy Markdown
Contributor

Description

When a pod starts while the config bundle is being rewritten, the first load can fail on a checksum mismatch or a missing part, and the watcher retries on every tick. Meanwhile the extproc reported SERVING, and the first AI request crashed it on the nil config. The sidecar then crash-looped and clients got empty 500s.

Until the first config is loaded:

  • Check and List report NOT_SERVING, so the pod stays out of rotation.
  • Known paths get a JSON 503 (gRPC Unavailable). Unknown paths still get 404.
  • The MCP proxy answers 503.

Server.config is now an atomic.Pointer, since health checks read it concurrently.

Related Issues/PRs (if applicable)

Fixes #2991

Special notes for reviewers (if applicable)

The config bundle watcher tolerates two errors on the initial load and
retries on the next tick: a part that doesn't match the index checksum,
and a listed part that is missing. Both happen when a pod starts while
the bundle is being rewritten. The external processor then served with
no config. Check reported SERVING, so the readiness probe passed and the
pod received traffic. The first request dereferenced the nil config, and
the panic killed the process. Envoy failed closed with an empty 500, and
the sidecar crash-looped until the bundle was consistent again and the
back-off expired.

Until the first config is loaded:
- Check and List report NOT_SERVING, so the readiness probe keeps the
  pod out of rotation.
- Streams for a registered path get an immediate 503 with a JSON error
  body and gRPC status Unavailable. Before, they crashed the process. An
  unregistered path still gets its 404.
- The MCP proxy answers 503. Before, it panicked in its handlers and
  dropped the connection.

Health checks now read the config while the watcher stores it, so
Server.config becomes an atomic.Pointer. The MCP proxy sets a loaded
flag after storing its config.

New tests start the external processor on an incomplete bundle and
check behaviour before the first load at four levels: the server, the
MCP proxy, the extproc binary's /health, and end to end through Envoy
(data-plane and data-plane-mcp). In each, requests are refused until
the bundle is repaired, and then served once the watcher loads it.

A pod that starts on a bundle that stays inconsistent now stays
NotReady, which also takes its non-AI routes out of rotation. Before,
it served them until the first AI request crashed the external
processor.

Signed-off-by: Abdulaziz Alharbi <calamitygaming64@gmail.com>
@abdulaziz-dev-lab
abdulaziz-dev-lab requested a review from a team as a code owner November 7, 2026 05:24
@netlify

netlify Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for theagentrouter canceled.

Name Link
🔨 Latest commit 6283e82
🔍 Latest deploy log https://app.netlify.com/projects/theagentrouter/deploys/6aeeb60c200bf5270c20d53d

@codecov

codecov Bot commented Nov 7, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

extproc panics and crash-loops when a request arrives before its first config load

1 participant