Repository navigation
Conversation
neuyilan
requested review from
andrewsykim,
kevin85421 and
rueian
as code owners
November 2, 2026 02:30
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The multi-slice E2E test still requires immediate reuse of a deleted Pod’s index, making its assertion timing-dependent when reconciliation reserves that index while the Pod is terminating.
1 open issue
What changed in this PR
This PR prevents stuck terminating worker Pods from indefinitely blocking RayCluster scaling, while preserving their replica indices until they disappear.
Changes:
- Allow delete expectations to expire after a timeout only once Pod deletion has started.
- Exclude terminating Pods from active reconciliation while reserving their indices, and log blocked expectations and terminating Pod names.
- Add regression tests for continued scaling, index reservation, and delete-timeout safeguards; remove sleep-based timeout testing.
| File | Description |
|---|---|
ray-operator/controllers/ray/raycluster_controller.go |
Separate active and terminating workers and reserve occupied replica indices. |
ray-operator/controllers/ray/raycluster_controller_unit_test.go |
Test scaling progress and index reservation with stuck terminating Pods. |
ray-operator/controllers/ray/expectations/scale_expectations.go |
Add guarded delete-expectation expiry and blocking diagnostics. |
ray-operator/controllers/ray/expectations/scale_expectations_test.go |
Test delete-timeout safeguards and use deterministic timestamps. |
Review effort: Balanced
| } | ||
| } | ||
| } | ||
| validReplicaIndices = replicaIndicesInUse |
…l Pod A worker group stops scaling (both up and down) indefinitely when a single worker Pod gets stuck in a terminal/terminating state (e.g. a Failed Pod whose node becomes NotReady, so the kubelet never confirms termination and the Pod keeps a deletionTimestamp that never clears). Root cause - two gates, both tripped by the same stuck Pod: 1. Scale-expectation gate (expectations/scale_expectations.go): isPodScaled() has a timeout fallback for Create but none for Delete. A Pod requested for deletion that never disappears keeps its Delete expectation unsatisfied forever; IsSatisfied() short-circuits on it, freezing all scaling. 2. Unhealthy-deletion early-return (raycluster_controller.go): even past gate kuberay-project#1, a Failed Pod is unconditionally judged shouldDelete=true, counted into numDeletedUnhealthyWorkerPods, triggering the early return before workersToDelete / replica-diff logic runs. The stuck Pod re-triggers this every reconcile. Fix: - scale_expectations.go: give the Delete branch a timeout fallback, but only after Kubernetes has set deletionTimestamp, so an expectation is never satisfied prematurely before deletion actually starts. - raycluster_controller.go: split out worker Pods that already have a deletionTimestamp (already terminating) so they no longer re-trigger unhealthy deletion or the early-return, and are skipped when draining workersToDelete. Terminating Pods still reserve their replica index so new Pods do not reuse it. - Observability: when Pods are stuck terminating, log their names (terminatingPodNames), not just a count, and log which Pod/action is blocking a group's reconcile. Tests: - TestIsPodScaledDeleteTimeout / TestIsPodScaledDeleteDoesNotTimeoutBeforeDeletion. - TestReconcilePodsStuckDeleteContinuesScaling / TestReconcilePodsStuckDeleteDoesNotReuseReplicaIndex. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: HouliangQi <qihouliang@xiaomi.com>
neuyilan
force-pushed
the
fix/worker-group-scaling-deadlock-stuck-pod
branch
from
November 2, 2026 02:43
6f6edae to
a823a2e
Compare
6 tasks
Signed-off-by: HouliangQi <qihouliang@xiaomi.com>
This branch has not been deployed
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.

A worker group stops scaling (both up and down) indefinitely when a single worker Pod gets stuck in a terminal/terminating state (e.g. a Failed Pod whose node becomes NotReady, so the kubelet never confirms termination and the Pod keeps a deletionTimestamp that never clears).
Root cause - two gates, both tripped by the same stuck Pod:
Fix:
Tests:
Why are these changes needed?
Related issue number
Labels
doc-updates-requiredlabel.breaking-changelabel.AI assistance
Checks
Manual test instructions