Skip to content

[core] Evict dead actors from ActorPool instead of recycling them - #64646

Open
verma-divyanshu-git wants to merge 10 commits into
ray-project:masterfrom
verma-divyanshu-git:actorpool-evict-dead-actor
Open

[core] Evict dead actors from ActorPool instead of recycling them#64646
verma-divyanshu-git wants to merge 10 commits into
ray-project:masterfrom
verma-divyanshu-git:actorpool-evict-dead-actor

Conversation

@verma-divyanshu-git

Copy link
Copy Markdown

Description

ActorPool.get_next / get_next_unordered returned the actor to the idle pool before ray.get() surfaced the actor's death. Because submit() pops from the end of the idle list, a dead actor was handed straight back out and every subsequent task on it failed, so a single bad actor could wedge the whole pool with no forward progress.

This recycles the actor only when it is still alive. On RayActorError the actor is dropped from the pool, while queued submits are still drained onto the remaining healthy actors. A normal task exception (RayTaskError) leaves the actor in the pool as before, since the actor itself is still healthy.

Related issues

Closes #50313

Additional information

Added test_dead_actor_is_evicted, which reproduces the issue (one actor that exits on its first task): it fails on master (the pool gets stuck and returns no results) and passes with this change. The existing test_actor_pool.py suite continues to pass.

@verma-divyanshu-git
verma-divyanshu-git requested a review from a team as a code owner July 9, 2026 21:06
Comment thread python/ray/util/actor_pool.py Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to evict dead actors from the ActorPool upon encountering a RayActorError. However, the feedback identifies critical bugs in both get_next and get_next_unordered where delaying the return of the actor until after ray.get(future) causes actors to leak from the pool if other exceptions (like RayTaskError) are raised. The reviewer suggests using a try...except...finally block to safely return actors in all scenarios. Additionally, the feedback points out a potential UnboundLocalError in get_next_unordered and recommends adding a unit test to ensure standard task errors do not cause actor leaks.

Comment thread python/ray/util/actor_pool.py Outdated
Comment thread python/ray/util/actor_pool.py Outdated
Comment thread python/ray/util/actor_pool.py
Comment thread python/ray/tests/test_actor_pool.py
ActorPool returned a crashed actor to the idle set, so submit() kept
dispatching to it and every following task failed with RayActorError.
_return_actor now tracks liveness and only puts the actor back when it is
still alive; a dead actor is dropped so the pool keeps making progress.

The actor is returned in a finally block and marked dead only on
RayActorError, so a normal task failure (RayTaskError) no longer leaks a
healthy actor from the pool.

Closes ray-project#50313

Signed-off-by: Divyanshu <bautocrats@gmail.com>
@verma-divyanshu-git
verma-divyanshu-git force-pushed the actorpool-evict-dead-actor branch from 56051f4 to dfdfb3d Compare July 9, 2026 21:18
Comment thread python/ray/util/actor_pool.py
@ray-gardener ray-gardener Bot added core Issues that should be addressed in Ray Core community-contribution Contributed by the community labels Jul 10, 2026
Comment thread python/ray/util/actor_pool.py Outdated

self._return_actor(a)
if raise_timeout_after_ignore:
self._return_actor(a)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if actor dies after timeout? the crash will be detected in the next task submission but we end up skipping the input (ie an innocent task will be sacrificed to detect the actor failure, and that task never gets retried as it is not the reason for the actor death)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

valid concern. i reproduced this locally. if a task times out and the actor dies afterward, the next task can be the one that sees the actor failure and gets lost.

this already happens on master. fixing it here would change the timeout behavior and make this pr larger than #50313 needs.

i think timed-out tasks need separate tracking so the actor is only reused after the original task finishes. if that sounds right, i can open a separate issue and pick it up in a follow-up pr.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if task times out we should probably call ray.cancel() instead of just ignoring the task and raising a timeout exception. but looks like ray.cancel() does not guarantee cancellation so we will need to go with the approach you are suggesting or introduce a new concept like task retries so that a failed task can be retried again on another actor if it failed due to actor death

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets add a todo for this scenario and take up fixing it in another pr

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ill merge this pr once u add this

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in a219c27 for both get_next and get_next_unordered. the TODO calls out that ignored tasks need to stay tracked and the actor should not be returned until the task finishes.

Comment thread python/ray/util/actor_pool.py
verma-divyanshu-git and others added 2 commits July 25, 2026 13:53
Use one path for ordered and unordered result retrieval so actor liveness handling stays consistent.

Signed-off-by: Divyanshu <bautocrats@gmail.com>
Comment thread python/ray/util/actor_pool.py
Only evict actors after a confirmed death so temporarily unavailable actors can recover and remain usable.

Signed-off-by: Divyanshu <bautocrats@gmail.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 77cca7f. Configure here.

Comment thread python/ray/util/actor_pool.py
@sampan-s-nayak sampan-s-nayak added the go add ONLY when ready to merge, run all tests label Jul 27, 2026
verma-divyanshu-git and others added 2 commits July 27, 2026 14:20
Document the delayed actor failure case for both ordered and unordered timeout paths.

Signed-off-by: Divyanshu <bautocrats@gmail.com>
@sampan-s-nayak
sampan-s-nayak enabled auto-merge (squash) July 27, 2026 15:31
@github-actions
github-actions Bot disabled auto-merge July 27, 2026 15:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-contribution Contributed by the community core Issues that should be addressed in Ray Core go add ONLY when ready to merge, run all tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Core] ray.util.ActorPool can get stuck in failing state with one bad actor

4 participants