Repository navigation
Conversation
neuyilan
requested review from
andrewsykim,
kevin85421 and
rueian
as code owners
October 28, 2026 06:31
Contributor
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues block approval of the changes addressing scaling deadlocks caused by stuck terminating Pods.
No open issues 🎉
What changed in this PR
This PR addresses worker-group scaling deadlocks in the Ray operator when a Pod remains stuck terminating.
Changes:
- Allow delete expectations to expire after a timeout, but only once the Pod has a deletion timestamp.
- Exclude terminating Pods from active-worker reconciliation while preserving their replica indices, and add diagnostic logging.
- Add regression tests for timeout safeguards, continued scaling, and replica-index preservation; remove sleep-based timing from the existing timeout test.
| File | Description |
|---|---|
ray-operator/controllers/ray/raycluster_controller.go |
Separates active and terminating workers, reserves replica indices, and logs terminating Pod names. |
ray-operator/controllers/ray/raycluster_controller_unit_test.go |
Tests continued scaling and index preservation with stuck terminating Pods. |
ray-operator/controllers/ray/expectations/scale_expectations.go |
Adds guarded delete-expectation expiry and logging for blocked reconciliation. |
ray-operator/controllers/ray/expectations/scale_expectations_test.go |
Tests delete-timeout behavior and replaces sleep-based timeout testing. |
Review effort: Balanced
Author
|
@rueian Could you please review it? thanks. |
Collaborator
|
Hi @neuyilan, could you fix the lint error as well as the DCO check? |
…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. Signed-off-by: HouliangQi <qihouliang@xiaomi.com>
neuyilan
force-pushed
the
fix/worker-group-scaling-deadlock-stuck-pod
branch
from
November 2, 2026 02:20
6f6edae to
60030c6
Compare
Author
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