daemon_log_e2e: the daemon does not publish its lockfile within 60s on BOTH CI platforms (105ms locally) #94
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
h-dv/code-index#94
Loading…
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?
What happened
a_detached_daemon_writes_a_log_beside_its_lockfiletimed out at the 60s deadline on both CI legs of the same commit (334f2c9):test result: FAILED. 3 passed; 1 failed; finished in 62.42stest result: FAILED. 3 passed; 1 failed; finished in 60.18sIt waits for the daemon to write
daemon listener bound; lockfile publishedinto its log.What is established
Locally the same step takes 105 ms, with near-zero variance (6/6 runs, 0.105–0.106s). The CI outcome is a ~570x outlier, not a slow machine.
Neither load axis reproduces it on this hardware:
Where the fault has to be
The suite's other three tests wait only for some log line (a
DEBUGline, or rotation). This is the only test that requires the daemon to get pastwrite_payload. So the stall or death sits in a ~10-line window incrates/daemon/src/main.rs:It is also the only test that runs with auth ON (
env_remove("CODE_INDEX_DAEMON_NO_AUTH")), sotoken: Some(..)andgenerate_token()(getrandom) are on its path and no other's.Leading unproven candidates, in order: the daemon was OOM-killed / evicted under the full-workspace suite (would explain both platforms and the load dependence, and is invisible on an idle box);
sync_data()stalling on slow CI storage;getrandomblocking.Root cause is NOT established and is deliberately not claimed here.
What has been done
The test could not previously tell a slow daemon from a dead one — it waited the full budget and printed the same sentence either way, which is why a 60s timeout arrived with nothing to go on. It now:
setup_logging;RPC server boundpresent but not the published line = thewrite_payloadgap; published line present = we were racing the poll.Deadline raised 60s -> 180s, so a genuinely slow-but-alive daemon is distinguished from a wedged one rather than being cut off at the same mark.
Both branches were mutation-proved (dead-daemon branch and alive-but-wedged branch each run RED with the diagnostic content).
Next step
The next CI occurrence names its own cause. Leave this open until a run prints the log content and the sub-case is identified.
SOLVED — and it was a defect in the TEST, not in the daemon
The instrument added when this was filed did exactly what it was built to do. On commit
4d8911bthe same test failed on both legs, but this time it printed its own cause:That one line eliminated every hypothesis in the issue body. Still RUNNING rules out the OOM kill and the crash. Log present but EMPTY rules out the
write_payloadwindow entirely — the daemon had not even written the"daemon log"line thatmain()emits immediately aftersetup_logging, long before the bind. A live process with an empty log is not a wedge; it is a level filter.The cause
setup_loggingfalls back toCODE_INDEX_LOGwhen--logis absent (main.rs), and this test deliberately omits--log— its own doc says why: the asserted line is aninfo, "the DEFAULT level a production daemon runs at".Both workflows set the variable job-wide:
So in CI the child inherited
warn, everyinfowas filtered, the file was created and stayed empty, and the test waited the full budget for a line that was never going to be written. It could not reproduce on a developer's machine because nothing sets that variable there.That also explains what looked inexplicable: both platforms, identically (it is the environment, not the OS), and no reproduction under 12-way CPU saturation or 8-way fsync load (it was never about load).
Proved, not argued
Byte-identical to the CI failure, on this Linux box. With
.env_remove("CODE_INDEX_LOG")added to the spawn, the same command is:The lesson worth keeping
The test already carried
.env_remove("CODE_INDEX_DAEMON_NO_AUTH")with a comment saying it was there "so an ambient value in the developer's shell cannot silently empty the assertion below". The identical hazard one line later, for the variable that decides whether the asserted line exists at all, was not handled. A test that asserts on log CONTENT must control the LEVEL, for the same reason it controls auth.Closing. The diagnostic stays: it is what turned a third occurrence into a five-minute answer instead of a fourth investigation.