跳转到内容
搜索文档

Durable Object 的生命周期

最后更新 查看 MarkdownAgent 设置

本节描述 Durable Object 的生命周期。

要使用 Durable Object,您需要创建一个 Durable Object Stub。 仅创建 Durable Object Stub 并不会向 Durable Object 发送请求,因此 Durable Object 尚未实例化。 只有在 Durable Object Stub 上调用方法后,请求才会发送到 Durable Object,其生命周期才开始。

const stub = env.MY_DURABLE_OBJECT.getByName("foo");
// Now the request is sent to the remote Durable Object.
const rpcResponse = await stub.sayHello();

Durable Object 生命周期状态转换

Durable Object 在任意时刻可处于以下状态之一:

状态 描述
Active, in-memory Durable Object 在内存中运行并处理传入请求。
Idle, in-memory non-hibernateable Durable Object 等待下一个传入请求/事件,但不满足休眠条件。
Idle, in-memory hibernateable Durable Object 等待下一个传入请求/事件且满足休眠条件。何时让 Durable Object 休眠由运行时决定。目前在此状态下不活跃 10 秒后会休眠。
Hibernated Durable Object 从内存中移除。已休眠的 WebSocket 连接保持连接。
Inactive Durable Object 完全从宿主进程中移除,可能需要冷启动。这是所有 Durable Objects 的初始状态。

以下是 Durable Object 在这些状态之间的转换方式(每个状态以圆角矩形表示)。

Durable Object 生命周期

假设 Durable Object 未在运行,第一个传入请求或事件(如 alarm)将执行 Durable Object 类的 constructor(),然后运行被调用的相应函数。

此时 Durable Object 处于 active in-memory 状态。

所有传入请求或事件处理完毕后,Durable Object 会在内存中空闲数秒,处于可休眠或不可休眠状态。

仅当所有以下条件均满足时,才能发生休眠:

  • 未设置 setTimeout/setInterval 计划回调,因为休眠后无法重建回调。
  • 没有进行中的 awaited fetch(),因为它被视为等待 I/O。
  • 未使用 WebSocket 标准 API。
  • 没有仍在处理的请求/事件,因为休眠意味着丢失本应最终向该请求返回响应的 async 函数。
  • 不存在活跃的出站 TCP 套接字(connect())或出站 WebSocket 连接。

在无传入请求或事件 10 秒且满足上述所有条件后,Durable Object 将转换到 hibernated 状态。

如果上述任一条件不满足,Durable Object 仍保留在内存中,处于 idle, in-memory, non-hibernateable 状态。

如果在 hibernated 状态下有传入请求或事件,constructor() 将再次运行,Durable Object 将转换到 active, in-memory 状态并执行被调用的函数。

idle, in-memory, non-hibernateable 状态下,不活跃 70-140 秒(无传入请求或事件)后,Durable Object 将完全从内存中驱逐,可能从 Cloudflare 宿主中移除,并转换到 inactive 状态。

hibernated 状态的对象保持 WebSocket 客户端连接,运行时决定是否以及何时将对象转换到 inactive 状态(例如决定将对象迁移到不同宿主),从而重启生命周期。

下一个传入请求或事件再次启动循环。

关闭行为

Durable Objects 偶尔会关闭并重启对象,这将运行您的 Durable Object 类构造函数。这可能由多种原因引起,包括:

  • 带有代码更新的新 Worker 部署
  • 根据上述状态转换,对象长时间无请求
  • Cloudflare 对 Workers 运行时系统的更新
  • Workers 运行时关于对象托管位置的决策

Durable Object 关闭时,对象实例会自动重启,新请求会路由到新实例。进行中的请求处理方式如下:

  • HTTP 和 RPC 请求:如果进行中的请求不访问 Durable Object 的存储,则允许完成。如果请求尝试访问 Durable Object 的存储,将立即停止并返回错误,以维护 Durable Objects 的全局唯一性属性。Workers 运行时系统更新时,进行中的请求最多有 30 秒完成时间。
  • WebSocket 连接:关闭期间 WebSocket 请求会自动终止。这样新实例可以尽快接管连接。
  • 其他调用(email、cron):其他调用与 HTTP 请求类似处理。

务必确保使用 Durable Objects 的任何服务都设计为能够处理 Durable Object 可能被关闭的情况。

代码更新

Durable Object 代码更新时,Worker 和 Durable Objects 会以最终一致的方式在全球发布。这将导致 Durable Object 关闭,行为如上所述。更新还可能导致请求到达某处的新版 Worker,而调用仍在其他地方运行旧版的 Durable Object。有关处理此场景的更多信息,请参阅代码更新

无关闭钩子时的处理

Durable Object 可能因部署、不活动或运行时决策而随时关闭。不要依赖关闭钩子(系统不提供),而应设计应用以增量方式写入状态。

不提供关闭钩子或关闭前运行的生命周期回调,因为 Cloudflare 无法保证这些钩子在所有情况下都会执行,且外部软件可能过度依赖这些(不可靠的)钩子。

与其依赖关闭钩子,你可以定期写入存储,以便从关闭中优雅恢复。

例如,如果你正在处理数据流并需要保存进度,应在处理过程中写入位置,而不是等到最后才持久化:

// Good: Write progress as you go
async processData(data) {
  data.forEach(async (item, index) => {
    await this.processItem(item);
    // Save progress frequently
    await this.ctx.storage.put("lastProcessedIndex", index);
  });
}

虽然这可能感觉违反直觉,但 Durable Object 存储写入快速且同步,因此你可以以极小的性能顾虑持久化状态。

这种方法确保 Durable Object 可以从任何点安全恢复,即使意外关闭也是如此。

这篇文档对您有帮助吗?