Skip to content

fix(controllers): reconcile not-Ready pods against their placeholder job#37

Open
cgetzen wants to merge 1 commit into
SlinkyProject:mainfrom
taichi-dev:fix/stale-pod-after-job-preemption
Open

fix(controllers): reconcile not-Ready pods against their placeholder job#37
cgetzen wants to merge 1 commit into
SlinkyProject:mainfrom
taichi-dev:fix/stale-pod-after-job-preemption

Conversation

@cgetzen

@cgetzen cgetzen commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #36.

The pod controller only reconciles a pod against its Slurm placeholder job while the pod is Running and Ready. A pod that never becomes Ready (crash-looping container, stuck in Init, failing readiness probe) is skipped on every reconcile. When Slurm preempts or cancels its placeholder job, the pod persists indefinitely. On DRA clusters the stale pod retains its ResourceClaim device allocation while Slurm reissues the freed GRES to the next job; the scheduler then stamps a second claim for the same device and the successor pod wedges in Init on NodePrepareResources ("requested device is already allocated to different claim"), requiring manual intervention.

This PR gates reconciliation on binding instead of readiness: A bound pod may exist only if its placeholder job is RUNNING. This is sound because the scheduler only binds a pod after its job starts, so post-bind, RUNNING is the only healthy job state.

Checklist

  • I have read
    CONTRIBUTING.md
    and the
    Code of Conduct.
  • New or existing tests cover these changes (where applicable).
  • Documentation is updated if user-visible behavior changes.

Breaking Changes

No API changes. Exactly one behavioral delta: bound pods that are not Ready are now reconciled — a crash-looping (or still-starting) pod whose placeholder job stops running is deleted instead of leaking forever. This is the fix. Bound Ready pods, unbound pods, and unlabeled pods have no behavior changes.

Testing Notes

  • Unit: go test ./internal/controller/... — ginkgo cases covering every combination: crash-looping (job running vs job gone), queued (job pending, job gone, unlabeled), bound-requeued, suspended, and bound-unlabeled orphan pods.
  • e2e on kind (hack/kind.sh --core): bridge-scheduled crash-looping pod (never Ready) + healthy control pod; scancel the crash-looper's placeholder job, results in pod deletion within one 30s reconcile (Deleting Pod for corresponding Slurm Job), claim released, healthy pod untouched.

The pod controller only reconciled pods that were Running and Ready, so
a pod that never became Ready (crash-looping, stuck in Init) was skipped
on every reconcile. When Slurm preempted or cancelled its placeholder
job, the pod leaked indefinitely while Slurm reissued the freed GRES to
the next job. The scheduler then stamped a second ResourceClaim for the
same device, and the successor pod wedged in Init on
NodePrepareResources ("requested device is already allocated to
different claim").

Gate reconciliation on binding instead of readiness: a bound pod may
exist iff its placeholder job is RUNNING. The scheduler binds a pod only
after its job starts, so RUNNING is the only healthy post-bind job state
- a bound pod whose job is terminal, gone, requeued, or suspended is
deleted regardless of readiness, releasing its resources on the
Kubernetes side before Slurm hands them to another job. Unbound pods are
never reconciled; the scheduler owns the pre-bind lifecycle.

Signed-off-by: Charlie Getzen <charliegetzen@meshy.ai>
@killianmuldoon

killianmuldoon commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Thanks for reporting and fixing this @cgetzen - I'll take a look.

@killianmuldoon killianmuldoon self-assigned this Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Wedged GPU accounting when pod is not ready

2 participants