跳转至

终止 Actor

当所有指向某个 Actor 的句柄(handle)在 Python 中被销毁或离开作用域,或者创建该 Actor 的主进程(creator process)退出时,相应的 Actor 进程也会自动终止。

如果你希望在 Actor 被正常(优雅)终止时执行一些资源清理操作(如释放连接、关闭文件等),可以在 Actor 类中实现 __ray_shutdown__() 方法。当 Actor 被销毁时,Ray 会自动调用该方法。

注意

目前 Java 和 C++ 的 Actor 还不支持自动终止机制。


通过 Actor 句柄手动终止

在大多数情况下,Ray 会自动终止那些已经离开作用域的 Actor,但有时你可能需要强制终止一个 Actor。

这种情况通常包括:

  • Actor 出现异常卡死(hanging)
  • Actor 存在资源泄漏(resource leak)
  • 对于 detached Actor(分离 Actor) —— 它们必须手动销毁
import ray

@ray.remote
class Actor:
    pass

actor_handle = Actor.remote()

ray.kill(actor_handle)
# Force kill: the actor exits immediately without cleanup.
# This will NOT call __ray_shutdown__() or atexit handlers.

这将导致 Actor 立即退出其所在进程,从而使当前、正在排队以及未来的所有任务都失败,并抛出 RayActorError

如果你希望 Ray 自动重启该 Actor,需要做到以下两点:

  • @ray.remote 的选项中为该 Actor 设置一个非零的 max_restarts
  • 在调用 ray.kill 时传入参数:no_restart=False

使用 State API 查看已死亡 Actor 的死亡原因

# This API is only available when you download Ray via `pip install "ray[default]"`
ray list actors --detail
-   actor_id: e8702085880657b355bf7ef001000000
class_name: Actor
state: DEAD
job_id: '01000000'
name: ''
node_id: null
pid: 0
ray_namespace: dbab546b-7ce5-4cbb-96f1-d0f64588ae60
serialized_runtime_env: '{}'
required_resources: {}
death_cause:
    actor_died_error_context: # <---- You could see the error message w.r.t why the actor exits.
        error_message: The actor is dead because `ray.kill` killed it.
        owner_id: 01000000ffffffffffffffffffffffffffffffffffffffffffffffff
        owner_ip_address: 127.0.0.1
        ray_namespace: dbab546b-7ce5-4cbb-96f1-d0f64588ae60
        class_name: Actor
        actor_id: e8702085880657b355bf7ef001000000
        never_started: true
        node_ip_address: ''
        pid: 0
        name: ''
is_detached: false
placement_group_id: null
repr_name: ''


在 Actor 内部手动终止

如果有需要,你也可以在 Actor 的某个方法内部手动终止该 Actor。

这样做会直接杀死该 Actor 所在的进程,并释放与该 Actor 相关或分配给它的资源。

@ray.remote
class Actor:
    def exit(self):
        ray.actor.exit_actor()

actor = Actor.remote()
actor.exit.remote()

通常来说,这种方式一般没有必要使用,因为 Actor 会被自动进行垃圾回收。

由该任务返回的 ObjectRef 可以用来等待 Actor 退出(如果对其调用 ray.get(),将会抛出 RayActorError)。

这种终止方式会等待所有之前提交的任务执行完成,然后通过 sys.exit() 优雅地退出进程

你可以看到,该 Actor 的死亡是由于用户调用了 exit_actor() 方法所导致的。

# This API is only available when you download Ray via `pip install "ray[default]"`
ray list actors --detail
-   actor_id: 070eb5f0c9194b851bb1cf1602000000
    class_name: Actor
    state: DEAD
    job_id: '02000000'
    name: ''
    node_id: 47ccba54e3ea71bac244c015d680e202f187fbbd2f60066174a11ced
    pid: 47978
    ray_namespace: 18898403-dda0-485a-9c11-e9f94dffcbed
    serialized_runtime_env: '{}'
    required_resources: {}
    death_cause:
        actor_died_error_context:
            error_message: 'The actor is dead because its worker process has died.
                Worker exit type: INTENDED_USER_EXIT Worker exit detail: Worker exits
                by a user request. exit_actor() is called.'
            owner_id: 02000000ffffffffffffffffffffffffffffffffffffffffffffffff
            owner_ip_address: 127.0.0.1
            node_ip_address: 127.0.0.1
            pid: 47978
            ray_namespace: 18898403-dda0-485a-9c11-e9f94dffcbed
            class_name: Actor
            actor_id: 070eb5f0c9194b851bb1cf1602000000
            name: ''
            never_started: false
    is_detached: false
    placement_group_id: null
    repr_name: ''


使用 __ray_shutdown__ 进行 Actor 清理

当一个 Actor 正常(优雅地)终止时,如果定义了 __ray_shutdown__() 方法,Ray 会自动调用该方法。

这使你可以在 Actor 退出时执行资源清理操作,例如:关闭数据库连接、释放文件句柄、清理其他外部资源等。

import ray
import tempfile
import os

@ray.remote
class FileProcessorActor:
    def __init__(self):
        self.temp_file = tempfile.NamedTemporaryFile(delete=False)
        self.temp_file.write(b"processing data")
        self.temp_file.flush()

    def __ray_shutdown__(self):
        # Clean up temporary file
        if hasattr(self, 'temp_file'):
            self.temp_file.close()
            os.unlink(self.temp_file.name)

    def process(self):
        return "done"

actor = FileProcessorActor.remote()
ray.get(actor.process.remote())
del actor  # __ray_shutdown__() is called automatically

__ray_shutdown__() 何时会被调用

✅ 会调用的情况:

  • 自动终止:当所有 Actor 句柄离开作用域时(例如 del actor 或自然作用域结束)
  • 手动优雅终止:当调用 actor.__ray_terminate__.remote()

❌ 不会调用的情况:

  • 强制杀死(Force kill):使用 ray.kill(actor),Actor 会被立即终止,不会执行清理逻辑
  • 异常终止:Actor 进程崩溃或异常退出,例如:段错误(segfault)被 OOM killer 杀死(内存不足)

Note

  • __ray_shutdown__() 会在 所有 Actor 任务执行完成之后 才运行
  • 默认情况下,Ray 会等待 30 秒 来完成优雅关闭流程(包括执行 __ray_shutdown__()),如果超过这个时间,Actor 会被强制终止。可以通过以下方式修改超时时间:
    ray.init(_system_config={"actor_graceful_shutdown_timeout_ms": 60000})
    
  • __ray_shutdown__() 中抛出的异常会被捕获并记录日志,但不会阻止 Actor 终止

  • __ray_shutdown__() 必须是同步方法(即使是 async Actor 也一样)