Nan Gao 5e3c24fe94
fix(gateway): probe the Redis stream bridge and provisioner in /health/ready (#6447)
* fix(gateway): probe the Redis stream bridge and provisioner in /health/ready

GET /health/ready only probed the ORM engine and the LangGraph checkpointer.
The Redis stream bridge client connects lazily and nothing ever pinged it, so a
Gateway whose Redis was down started, answered 200 ready to the Kubernetes
readinessProbe and Compose healthcheck, and kept receiving traffic while every
run's first publish failed. Since #6328 the Redis bridge is mandatory for
multi-instance deployments, so such a replica is not serviceable at all.

- StreamBridge gains `async ping() -> bool`; the base returns True (no external
  backend), RedisStreamBridge round-trips PING and answers False on RedisError.
- /health/ready adds a `stream_bridge` probe (not_configured for the memory
  bridge; unreachable flips the endpoint to 503; a missing bridge fails closed)
  and a report-only `provisioner` probe of `{sandbox.provisioner_url}/health`
  that never changes the status code, since every replica shares one
  provisioner. The provisioner URL is snapshotted on app.state at startup.
- A probe that overruns the endpoint deadline is now the only one marked
  unreachable; finished verdicts are kept.
- The public probe gate is one lock per probe kind, so one request's probes
  still run concurrently while a thundering herd opens at most one probe
  connection per kind per process.
- Tests: bridge ping cases, stream-bridge/provisioner probe cases, verdict and
  deadline cases, and the first route-level /health/ready tests via TestClient.
- Docs: gateway AGENTS.md, CONFIGURATION.md multi-instance notes, Helm README
  and probe comment, Compose healthcheck comment.

* docs(changelog): note the readiness probe fix (#6447)

* fix(gateway): apply the sandbox proxy policy to the provisioner probe

Review follow-up for #6447.

- The provisioner readiness probe built its httpx client with the default
  trust_env=True. httpx 0.28 treats CIDR entries in NO_PROXY as host patterns
  rather than subnet bypasses, so with HTTP_PROXY set and NO_PROXY=10.0.0.0/8
  a private provisioner that the requests-based sandbox calls reach directly
  would have been probed through the proxy and reported unreachable on every
  check. The probe now reuses `sandbox_http_trust_env`: loopback, private,
  link-local and cluster-local addresses bypass the proxy, external hosts keep
  the environment's proxy settings.
- Pin the liveness/readiness separation with a route test: `GET /health`
  stays 200 while the stream bridge and database are unreachable and
  `/health/ready` is 503, so a Redis blip can never become a restart loop.
2026-10-08 06:56:33 +08:00
..