fix(controller): mark RUN jobs unknown on worker loss and restart (bug-1509 P2)

Phase 2 of the job-finish robustness design (Part B, B1+B3).

B1 (worker liveness): a worker that stops reporting (heartbeat timeout,
already detected by check_worker_timeout_) or disconnects now has its RUN
jobs marked JOB_STAT_UNKWN|JOB_STAT_TRANSIENT (transient_since set, durable
WAL_JOB_UPDATE) instead of lingering as RUN forever. Marking happens
AFTER the worker lock is released (B5: avoids worker->jobmgr inversion
with the scheduler's jobmgr->worker order).

B3 (restart): persist_recover marks all recovered RUN jobs UNKWN+TRANSIENT
in-memory after replay — a controller restart leaves worker connectivity
unknown. In-memory only (no WAL append) because persist_recover may run
on a future standby that must never append.

Unit tests (red->green): worker-loss marks its RUN jobs unknown, other-host
jobs untouched, restart marks all RUN jobs. test_replay_apply_seam updated:
replay still drives facts to RUN, then B3 adds UNKWN+TRANSIENT.
This commit is contained in:
lei.chen 2026-08-06 05:57:59 +00:00
parent a793015f74
commit fc091348e8
7 changed files with 224 additions and 4 deletions

View file

@ -361,9 +361,15 @@ static void test_replay_applies_every_classified_type_via_apply_seam(void)
TEST_ASSERT_NOT_NULL_MESSAGE(j,
"replay must construct the job via the apply seam's "
"WAL_JOB_SUBMIT route");
TEST_ASSERT_EQUAL_UINT32_MESSAGE(JOB_STAT_RUN, j->job.state,
/* bug-1509 B3: after recovery, RUN jobs' state is uncertain (worker
* connectivity unknown), so persist_recover marks them UNKWN+TRANSIENT
* in-memory. The replay itself must still drive the fact to RUN; the
* UNKWN/TRANSIENT bits come from B3's post-replay marking. */
TEST_ASSERT_EQUAL_UINT32_MESSAGE(JOB_STAT_RUN | JOB_STAT_UNKWN
| JOB_STAT_TRANSIENT,
j->job.state,
"replay must apply the job-state fact via the apply seam's "
"guarded transition core, reaching the same end state as before");
"guarded transition core, then B3 marks the RUN job UNKWN");
queue_t* q = trr_find_queue("rq1");
TEST_ASSERT_NOT_NULL(q);