fix(spurctld): report BeginTime while --begin defers a job - #555
Draft
maybeharshit wants to merge 2 commits into
Draft
fix(spurctld): report BeginTime while --begin defers a job#555maybeharshit wants to merge 2 commits into
maybeharshit wants to merge 2 commits into
Conversation
A job held back by --begin sat in PENDING with Reason=None, the same string shown for a job the scheduler has not reached yet, so nothing distinguished a deliberate deferral from an idle pass. Visible identically through squeue, scontrol, and the REST state_reason field. classify_pending_jobs marked such a job scheduling_eligible = false and then dropped it at the final retain without ever pushing it onto the blocked list that feeds apply_blocked_pending_reasons. It reached no blocker check either, since those all pass ineligible candidates straight through, so no code path could name its wait. The filter at the top of the function already short-circuits jobs tagged BeginTime, so a tagger was anticipated but never written. Record the hold at that final retain, keyed on the existing is_begin_held predicate so only a genuine begin-time deferral is tagged. Placing it after the blocker checks preserves their precedence: a job that also sits in a down partition still reports the partition, which explains why it cannot run at all rather than naming a start time it will never reach. The consumable-reason test changes expectation as a result. It asserted that a deferred job's reason was left untouched as a proxy for "no license or burst-buffer shortage was recorded"; that invariant still holds, since those checks continue to skip ineligible candidates, but the reason is now the deferral rather than whatever the job carried before. Co-authored-by: Cursor <cursoragent@cursor.com>
maybeharshit
requested review from
powderluv,
sajmera-pensando,
sgopinath1,
shiv-tyagi and
yansun1996
as code owners
July 31, 2026 08:40
maybeharshit
marked this pull request as draft
July 31, 2026 10:50
Member
|
Hi @maybeharshit , you marked this PR as draft, are you still working on more changes ? |
shiv-tyagi
reviewed
Aug 4, 2026
Comment on lines
+2218
to
+2221
| // A begin-deferred job reaches none of the blocker checks above, which | ||
| // all pass ineligible candidates straight through, so this is the only | ||
| // place its wait can be named. Structural blockers already claimed the | ||
| // jobs they explain, keeping their precedence over the hold. |
Member
There was a problem hiding this comment.
Nit: this is slightly verbose for what it communicates. The first sentence is the insight; the rest restates what's visible from the surrounding code (the blocker checks all return true for ineligible candidates).
Suggested change
| // A begin-deferred job reaches none of the blocker checks above, which | |
| // all pass ineligible candidates straight through, so this is the only | |
| // place its wait can be named. Structural blockers already claimed the | |
| // jobs they explain, keeping their precedence over the hold. | |
| // This is the only tagger for begin-deferred jobs: the blocker checks | |
| // above pass ineligible candidates through without claiming them. |
Trim the restatement of the surrounding code while keeping the precedence rationale (a structural blocker still outranks the hold). Comment only. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A job held back by
--beginsat inPENDINGwithReason=None— the same string shown for a job the scheduler has simply not reached yet. Nothing distinguished a deliberate deferral from an idle scheduling pass, onsqueue,scontrol show job, or the RESTstate_reasonfield. Slurm reportsBeginTimefor this case.Fixes #547.
Technical Details
classify_pending_jobsmarked a begin-deferred jobscheduling_eligible = falseand then dropped it at the closingcandidates.retain(...)without ever pushing it onto theblockedlist that feedsapply_blocked_pending_reasons. It reached none of the blocker checks either, since those all pass ineligible candidates straight through, so no code path could name its wait.PendingReason::BeginTimewas therefore only ever set by the preemption-requeue path.Notably, the filter at the top of the same function already short-circuits jobs that are begin-held and already tagged
BeginTime, so a tagger was anticipated — it was just never written.The hold is now recorded at that final
retain, keyed on the existingJob::is_begin_heldpredicate rather than on!scheduling_eligible, so only a genuine begin-time deferral is tagged.Two consequences of where it sits:
[1] Placing it after the blocker checks preserves their existing precedence. A deferred job that also sits in a down partition still reports
PartitionInactive, which explains why it cannot run at all, rather than naming a start time it will never reach. There is a test for this.[2] Consumable shortages (licenses, burst buffer) continue to be skipped for deferred jobs. Those are transient and may well be resolved by the time the start time arrives, so the hold is the honest reason to show.
The scheduler loop already calls
pending_jobs_and_tag_reasons()before itspending.is_empty()early return, specifically so reasons stay fresh when nothing is schedulable — which is exactly the issue's single-deferred-job-on-an-idle-cluster scenario, so no change was needed there.Note on a changed test expectation
future_begin_jobs_do_not_receive_consumable_block_reasonsasserted that a deferred job's reason was left untouched, using that as a proxy for "no consumable shortage was recorded". That invariant still holds — the license and burst-buffer checks continue to skip ineligible candidates — but the proxy no longer works, since the reason is now the deferral instead of whatever the job carried before. The assertions were updated to name the real invariant.Test Plan
spurctldfor the deferral being tagged, the reason giving way once the hold lapses, and a structural blocker outranking the hold. The first two were confirmed to fail without the fix.tests/native_host/e2e/test_begin_time.pycovering the reported flow plus a control job with no--begin.Test Result
Clippy and fmt clean; full workspace suite passes. Both new unit tests fail on
mainwithleft: None, right: BeginTime, matching the reported symptom exactly.On the LXD cluster,
sbatch --begin=now+40seconds ok.sh:The REST surface named in the issue agrees —
GET /slurm/v0.0.42/job/2returnedjob_state = PENDINGwithstate_reason = BeginTime.The deferral itself still works: the job started 41 seconds after submit for a 40-second
--begin, ran to completion, and its reason did not remain stuck atBeginTime.Submission Checklist
Made with Cursor