mirror of
https://github.com/kvcache-ai/AgentENV.git
synced 2026-11-05 01:17:36 +00:00
[GH-ISSUE #447] Scheduler gRPC health keeps passing while node discovery is dead — silent multi-day wedge (production incident 2026-10-28) #109
Labels
No labels
bug
documentation
enhancement
enhancement
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
kvcache-ai/AgentENV#109
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @mingfang on GitHub (Oct 28, 2026).
Original GitHub issue: https://github.com/kvcache-ai/AgentENV/issues/447
Summary
In production (v0.2.4) the scheduler pod sat
Running 1/1with zero restarts for 39 hours while being functionally dead: every template/build operation through it failed. Kubernetes never restarted it because its liveness and readiness probes (exec /grpc_health_probe -addr=127.0.0.1:9090) kept passing the whole time.Evidence
failed to list *v1.EndpointSlice: ... dial tcp 172.27.0.1:443: connect: connection refusedwatch of *v1.EndpointSlice ended with: an error on the server ("unable to decode an event from the watch stream: http2: client connection lost")grpc_health_probeSERVING throughout.Root cause of the detection gap
The gRPC health service only proves the process is alive, not that node discovery works. A dead EndpointSlice watch is invisible to
grpc_health_probe.Proposed fix
Make the scheduler's gRPC health reflect registry freshness, so the existing k8s probes auto-heal (restart) within ~1 minute:
s.nodes.ListObservedalready knows heartbeat freshness —services/scheduler/internal/service.go:263refreshObservedNodesMetrics).NOT_SERVINGwhen no node heartbeat has been recorded for N minutes while the deployment expects nodes.agentenv_scheduler_watch_last_event_age_secondsmetric on :9101 so the dead-watch state is observable from the outside (today onlyagentenv_scheduler_observed_nodes{status=...}exists, which is heartbeat-based and can stay 1 on a stale cache).Relevant code:
services/scheduler/internal/kubernetes_discovery.go,services/scheduler/internal/service.go,services/scheduler/internal/metrics.go,services/scheduler/cmd/main.go:93.Mitigation deployed meanwhile
An external watchdog CronJob polls
agentenv_scheduler_observed_nodes{status="ready"}every 5 min, alerts, and restarts the pod once the zero persists past the startup window (heal latency ≤ ~10 min). The in-process health fix would make all of that redundant and cut the window to the probe period.