feat(worker-rejoin-resync): reconcile unrecognized job to pending (task 2.1)
Add record_job_reconcile_pending_fact(cluster_t*, job_t*) to job.c: eagerly applies apply_job_update_transition(job, JOB_STAT_PEND) (real, live mutation, not a deferred peek -- matching dispatch_a_job_'s established pattern, not record_job_finish_fact's), releases job->job.allocs on an applied (non-no-op) transition, then durably appends via the generic persist_submit_job_fact(WAL_JOB_UPDATE). Caller holds job's lock throughout and is responsible for calling persist_notify_job_updated_already_persisted() after unlocking -- this function deliberately does not call it itself. Closes bug-1631 at this new call site: a RUN job with a real allocation reconciled to PEND (Requirement 4.6, worker reports it unrecognized) would otherwise carry a stale allocation into its next dispatch attempt, exactly the gap bug-1631 documented as dormant until something re-admits an already-dispatched job to the scheduler's PEND pool -- this feature is that path. dispatch_a_job_ itself is unchanged (still correct for a job's first-ever dispatch, the only case reachable there). 3 tests: allocs release + eager-mutation-before-unlock proof, no-op on already-pending, and the Requirement 4.4 terminal-state-preservation proof (rejects overwriting JOB_STAT_DONE). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y4M5MJM2zK6nU43da267Ku
This commit is contained in:
parent
eda2eb1bf0
commit
cfe66dde16
7 changed files with 433 additions and 2 deletions
|
|
@ -183,6 +183,34 @@ extern job_transition_result_t apply_job_update_transition(job_t*, int);
|
|||
* RTTI_LOCK_WRITE. */
|
||||
extern job_transition_result_t apply_job_postdone_transition(job_t*);
|
||||
|
||||
/* worker-rejoin-resync task 2.1 (Req 4.6, 5.4, 7.1-7.3): returns a job the
|
||||
* worker reports as unrecognized back to PEND, releasing any resource
|
||||
* allocation it was carrying (bug-1631) so a later redispatch never
|
||||
* inherits a stale allocation from the prior dispatch. Follows
|
||||
* dispatch_a_job_()'s own eager-mutation-plus-explicit-notify pattern, NOT
|
||||
* record_job_finish_fact's deferred one -- see design.md's "Controller:
|
||||
* job.c" Components section for the full rationale.
|
||||
*
|
||||
* Precondition: caller holds `job` under RTTI_LOCK_WRITE on entry and does
|
||||
* not release it until this call returns -- matching apply_job_update_
|
||||
* transition's own calling convention (e.g. mark_job_update's callers).
|
||||
* This function does not lock/unlock `job` itself.
|
||||
*
|
||||
* Returns the job_transition_result_t of the underlying apply_job_update_
|
||||
* transition(job, JOB_STAT_PEND) call, cast to int, so the caller can tell
|
||||
* JOB_TRANSITION_APPLIED apart from JOB_TRANSITION_REJECTED_BACKWARD/
|
||||
* JOB_TRANSITION_NOOP_DUPLICATE exactly as that guard's other callers
|
||||
* already do. Only on JOB_TRANSITION_APPLIED does this function release
|
||||
* job->job.allocs (if non-NULL) and durably append the fact -- a rejected
|
||||
* or no-op outcome touches neither (Req 4.3/4.4).
|
||||
*
|
||||
* Unlike record_job_finish_fact/record_job_fail_fact, the caller (not this
|
||||
* function) must call persist_notify_job_updated_already_persisted(c, job)
|
||||
* itself, AFTER releasing the write lock, exactly once, whenever this
|
||||
* returns JOB_TRANSITION_APPLIED -- omitting it reproduces bug-1679 at this
|
||||
* call site. */
|
||||
extern int record_job_reconcile_pending_fact(cluster_t*, job_t*);
|
||||
|
||||
extern int on_job_start(cluster_t*, job_pidinfo_t*);
|
||||
extern int on_job_finish(cluster_t*, xce_jobfinish_t*);
|
||||
extern int on_job_fail(cluster_t*, job_failinfo_t*);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue