Repository navigation
fix(health): fail readiness on essential worker/scheduler errors (E07) - #3704
Conversation
Diligence E07: /readiness returns 503 when the ingestion worker errors (startup failure or dead thread), and when the embedded scheduler errors while SCHEDULER_EMBEDDED enables it. Neo4j and the rate limiter stay non-blocking. /health remains a separate liveness probe so Railway does not couple restarts to background-unit death alone. Signed-off-by: Christopher Sellers <1@christophersellers.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review.
|
PetrefiedThunder
left a comment
There was a problem hiding this comment.
Codex review — RegEngine #3704 (E07 readiness)
Commit: 56c6238daf14db7d838d580fc8c942d4c7552821
Spec: reliability-E07-E09-decision-2026-10-28.md (E07)
Scope: server/main.py (_readiness_checks), tests/test_server_readiness_probe.py
Verdict
PASS — readiness gating matches the E07 essential-unit contract; /health is untouched and remains a separate liveness probe; focused tests are data-free and cover the listed behaviors.
Verify map
| Requirement | Result |
|---|---|
| Worker startup failure → 503 | Yes — worker_essential_error + test_worker_start_failure_returns_503 |
| Worker dead thread → 503 | Yes — thread.is_alive() + test_worker_dead_thread_returns_503 |
| Scheduler error → 503 only when embedded | Yes — gate uses embedded_scheduler_enabled(); embedded vs not-embedded tests for start failure and dead thread |
| Neo4j / rate limiter non-blocking | Yes — informational only; test_e07_neo4j_error_stays_non_blocking, test_e07_rate_limiter_error_alone_stays_non_blocking |
| Recovers to 200 after healthy restart | Yes — test_e07_readiness_recovers_to_200_after_restart (failed then healthy app.state) |
/health liveness unchanged |
Yes — PR does not modify services/ingestion/app/routes_health_metrics.py (sole GET /health owner); no worker/scheduler refs there |
| Spec match | Yes — essential units fail readiness; disabled/not_configured/neo4j/rate limiter stay non-blocking; liveness kept separate (Railway restart-loop concern) |
| Thread liveness races | No unsafe race — local thread capture + is_alive() / thread_alive property; post-sample death is caught on the next probe (within the 2‑minute staging window) |
| Data-free tests | Yes — minimal FastAPI apps, monkeypatch, stubs; no live DB/Redis/Neo4j |
Local checks
pytest tests/test_server_readiness_probe.py -q→ 33 passed- Head re-verified:
56c6238daf14db7d838d580fc8c942d4c7552821
Notes (non-blocking)
- P2 / nit:
test_e07_liveness_unaffected_when_essential_unit_failsregisters a fabricated/healththat always returns alive. Source inspection confirms the real handler is unchanged and decoupled; mounting the real health router on the minimal app would harden the regression. - Out of scope for this PR: E07 staging acceptance (inject/kill units, alert timing, deploy non-promotion) remains Reliability-owned per the spec. Unit recovery is state-swap, not a process restart.
- CI at review time still had pending/failing gate jobs (
Head SHA Check Guard,PR Blocker Checklist); not treated as a code-contract fail.
No merge performed.
REVIEW: PASS codex 56c6238
PR Blocker ChecklistHead SHA: Status: Ready
|
PetrefiedThunder
left a comment
There was a problem hiding this comment.
REVIEW: PASS pi 56c6238
E07 readiness: worker error always 503; scheduler error 503 only when SCHEDULER_EMBEDDED enables it; neo4j/rate_limiter stay non-blocking; /health unchanged. Tests green (tests/test_server_readiness_probe.py). Scope matches diligence; no secrets/tenant issues.
Summary
Diligence E07 (backend readiness): make
/readinessfail promotion when essential background units are down, while keeping/healthas a separate liveness probe.Specs:
/workspace/regengine-diligence/reliability-E07-E09-decision-2026-10-28.mdand the E07 section ofdevops-plan-E07-E09-E13-2026-10-28.md.No Railway deploy / redeploy / rollback (including
1a6d30d0). Codex will review.Requirement → code → tests
error(startup failure)server/main.py_readiness_checksgate:worker_essential_errortest_worker_start_failure_returns_503is_alive()check + new gatetest_worker_dead_thread_returns_503SCHEDULER_EMBEDDEDenables itembedded_scheduler_enabled()test_scheduler_start_failure_returns_503_when_embedded,test_scheduler_dead_thread_returns_503_when_embeddeddisabled/ not embedded stays non-blockingtest_scheduler_disabled_is_healthy,test_scheduler_*_when_not_embeddedtest_e07_neo4j_error_stays_non_blocking(+ existing neo4j tests)test_e07_rate_limiter_error_alone_stays_non_blockingtest_e07_readiness_recovers_to_200_after_restart/healthuntouched; readiness-only gatetest_e07_liveness_unaffected_when_essential_unit_fails(+ existing stalled-probe liveness test)Files
server/main.py— readiness gate + commentstests/test_server_readiness_probe.py— contract updates + E07 casesOverlaps avoided
Open red PRs were inventoried first. None touch
server/main.pyortests/test_server_readiness_probe.py. Stayed off the main-red secrets baseline fix (#3703 / #3700).Local verification
Notes / ambiguities
thread.is_alive()/thread_alivechecks (immediate on the next/readinesspoll). No new heartbeat window was added.Note
Medium Risk
Changes deploy promotion behavior when ingestion or embedded scheduler is down; well-scoped to the readiness gate with broad test coverage, but misconfiguration could block healthy deploys or delay catching worker issues until promotion.
Overview
Implements diligence E07 by tightening
/readiness(Railway’s deploy healthcheck) so broken background work cannot promote, while/healthstays a separate liveness probe.Essential units now return HTTP 503: ingestion worker startup failure or a dead worker thread always fails readiness. Embedded scheduler startup failure or a dead scheduler thread fails readiness only when
SCHEDULER_EMBEDDEDenables it viaembedded_scheduler_enabled();disabled/not_configuredscheduler states stay non-blocking.Still non-blocking alone: Neo4j and rate-limiter problems remain in the
checkspayload (200degradedwhen Postgres/Redis/essential units are OK). Postgres and strict-runtime Redis rules are unchanged.Tests in
test_server_readiness_probe.pywere updated for the new contract and add E07 cases (Neo4j/rate limiter alone, recovery after restart, liveness vs readiness).Reviewed by Cursor Bugbot for commit 56c6238. Bugbot is set up for automated code reviews on this repo. Configure here.