Client or integration
OpenCodex dashboard
Area
Service lifecycle
Summary
On Windows, ocx service repair can report failure at its fixed 20-second health deadline even though the scheduled service is still starting and becomes healthy immediately afterward.
I saw this while recovering a dashboard update on 2.36.0. The repair command printed that no proxy answered on port 11000 within 20 seconds and returned exit 1. The Task Scheduler job remained running. Shortly afterward, /healthz returned status: ok from the same scheduled startup, and the proxy remained stable.
Expected: a slow but valid Windows cold start should not be reported as a terminal repair failure. A final probe at the deadline, or a slightly longer/phase-aware bounded wait, would avoid the false negative while still failing a service that never binds.
Reproduction
- Install OpenCodex 2.36.0 through npm on Windows.
- Install the
opencodex-proxy Task Scheduler service.
- Use an environment where startup work can take around 20 seconds. In this run the service log also showed an NTFS ACL hardening timeout and previous-session journal recovery before the proxy announced its listener.
- Run
ocx service repair.
- Observe the command exit 1 after the 20-second serving check.
- Check the scheduled task and
/healthz a few seconds later. The same service startup is running and healthy.
Observed command result:
Service repaired, but no proxy answered on port 11000 within 20s.
Follow-up state:
{
"status": "ok",
"service": "opencodex",
"version": "2.36.0",
"pid": 39388,
"port": 11000
}
The process was created at 2026-08-30T21:33:19+08:00; the scheduled task run was recorded at 21:33:33+08:00. After it became healthy, repeated checks and the Web UI stayed available. This was not a crash/restart loop.
The current code uses one fixed deadline:
export const SERVICE_INSTALL_HEALTH_MS = 20_000;
and returns failure as soon as that deadline is reached. A final identity probe at the boundary would at least close the narrow race. If 20 seconds is intentionally the normal budget, a separate bounded grace period for a still-running Windows service may be another option.
Related but not duplicate: #720 fixed the GUI update worker's 15-second restart-confirmation boundary. This report is the separate confirmServiceServing() path used by service install/start/repair, which still has a 20-second deadline on current main.
Version
2.36.0; current main still uses the 20-second service-install health deadline.
Operating system
Windows 10 22H2, build 19045, x64
Provider and model
Not provider-specific
Logs or error output
[opencodex] ACL hardening timed out (ETIMEDOUT) — continuing without NTFS ACL harden
Previous session did not shut down cleanly. Codex state restored from journal.
opencodex proxy running on http://localhost:11000
Screenshots and supporting files
Current source: https://github.com/lidge-jun/opencodex/blob/main/src/service.ts#L554-L617
Redacted configuration
{
"installer": "npm",
"service": "Windows Task Scheduler",
"port": 11000
}
Checks
Client or integration
OpenCodex dashboard
Area
Service lifecycle
Summary
On Windows,
ocx service repaircan report failure at its fixed 20-second health deadline even though the scheduled service is still starting and becomes healthy immediately afterward.I saw this while recovering a dashboard update on 2.36.0. The repair command printed that no proxy answered on port 11000 within 20 seconds and returned exit 1. The Task Scheduler job remained running. Shortly afterward,
/healthzreturnedstatus: okfrom the same scheduled startup, and the proxy remained stable.Expected: a slow but valid Windows cold start should not be reported as a terminal repair failure. A final probe at the deadline, or a slightly longer/phase-aware bounded wait, would avoid the false negative while still failing a service that never binds.
Reproduction
opencodex-proxyTask Scheduler service.ocx service repair./healthza few seconds later. The same service startup is running and healthy.Observed command result:
Follow-up state:
{ "status": "ok", "service": "opencodex", "version": "2.36.0", "pid": 39388, "port": 11000 }The process was created at
2026-08-30T21:33:19+08:00; the scheduled task run was recorded at21:33:33+08:00. After it became healthy, repeated checks and the Web UI stayed available. This was not a crash/restart loop.The current code uses one fixed deadline:
and returns failure as soon as that deadline is reached. A final identity probe at the boundary would at least close the narrow race. If 20 seconds is intentionally the normal budget, a separate bounded grace period for a still-running Windows service may be another option.
Related but not duplicate: #720 fixed the GUI update worker's 15-second restart-confirmation boundary. This report is the separate
confirmServiceServing()path used by service install/start/repair, which still has a 20-second deadline on currentmain.Version
2.36.0; current
mainstill uses the 20-second service-install health deadline.Operating system
Windows 10 22H2, build 19045, x64
Provider and model
Not provider-specific
Logs or error output
Screenshots and supporting files
Current source: https://github.com/lidge-jun/opencodex/blob/main/src/service.ts#L554-L617
Redacted configuration
{ "installer": "npm", "service": "Windows Task Scheduler", "port": 11000 }Checks