SuperAPI AI 工具集

durable-objects

编程与开发

查看项目

更新于 10-15 08:33

技能介绍

用途

该技能面向在 Cloudflare 边缘平台上使用 Durable Objects 构建有状态、可协调应用的开发场景。适用于创建新的 Durable Object 类以实现有状态协调、实现 RPC 方法、闹钟或 WebSocket 处理器、审查现有 DO 代码是否符合最佳实践、配置 wrangler.jsonc/toml 的 DO 绑定与迁移、使用 Cloudflare 的 Vitest 集成编写测试,以及设计分片策略和父子关系。

主要能力

技能提供检索来源指引,建议在实现功能时获取相关文档页面,因为对 Durable Objects API 和配置的知识可能已过时,任何 DO 任务都应优先检索而非依赖预训练。检索资源包括:文档(https://developers.cloudflare.com/durable-objects/index.md)、API 参考(https://developers.cloudflare.com/durable-objects/api/index.md)、最佳实践(https://developers.cloudflare.com/durable-objects/best-practices/index.md)、示例(https://developers.cloudflare.com/durable-objects/examples/index.md)、角色与权限(https://developers.cloudflare.com/workers/authorization/durable-objects/index.md)。

参考文档包括:./references/rules.md(核心规则、存储、并发、RPC、闹钟)、测试参考(当前 Vitest 文档、迁移选择与测试选择)、./references/workers.md(Workers 处理器、类型、wrangler 配置、可观测性)。可搜索关键词:blockConcurrencyWhile、idFromName、getByName、setAlarm、sql.exec。

使用方式

Wrangler 配置示例:

// wrangler.jsonc
{
  "durable_objects": {
    "bindings": [{ "name": "MY_DO", "class_name": "MyDurableObject" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyDurableObject"] }]
}

基础 Durable Object 模式:

import { DurableObject } from "cloudflare:workers";

export interface Env {
  MY_DO: DurableObjectNamespace<MyDurableObject>;
}

export class MyDurableObject extends DurableObject<Env> {
  constructor(ctx: DurableObjectState, env: Env) {
    super(ctx, env);
    ctx.blockConcurrencyWhile(async () => {
      this.ctx.storage.sql.exec(`
        CREATE TABLE IF NOT EXISTS items (
          id INTEGER PRIMARY KEY AUTOINCREMENT,
          data TEXT NOT NULL
        )
      `);
    });
  }

  async addItem(data: string): Promise<number> {
    const result = this.ctx.storage.sql.exec<{ id: number }>(
      "INSERT INTO items (data) VALUES (?) RETURNING id",
      data
    );
    return result.one().id;
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const stub = env.MY_DO.getByName("my-instance");
    const id = await stub.addItem("hello");
    return Response.json({ id });
  },
};

Stub 创建方式:

// 确定性 - 多数情况下首选
const stub = env.MY_DO.getByName("room-123");

// 从已有 ID 字符串创建
const id = env.MY_DO.idFromString(storedIdString);
const stub = env.MY_DO.get(id);

// 新唯一 ID - 需在外部存储映射
const id = env.MY_DO.newUniqueId();
const stub = env.MY_DO.get(id);

存储操作:

// SQL(同步,推荐)
this.ctx.storage.sql.exec("INSERT INTO t (c) VALUES (?)", value);
const rows = this.ctx.storage.sql.exec<Row>("SELECT * FROM t").toArray();

// KV(异步)
await this.ctx.storage.put("key", value);
const val = await this.ctx.storage.get<Type>("key");

闹钟:

// 调度(替换现有闹钟)
await this.ctx.storage.setAlarm(Date.now() + 60_000);

// 处理器
async alarm(): Promise<void> {
  // 处理计划任务
  // 可选重新调度:await this.ctx.storage.setAlarm(...)
}

// 取消
await this.ctx.storage.deleteAlarm();

适用场景

适合使用 Durable Objects 的场景包括:协调(聊天室、多人游戏、协作文档)、强一致性(库存、预订系统、回合制游戏)、按实体存储(多租户 SaaS、按用户数据)、持久连接(WebSocket、实时通知)、按实体的计划任务(订阅续订、游戏超时)。

不适合使用的场景包括:无状态请求处理(应使用普通 Workers)、需要最大全球分布、高扇出的独立请求。

关键规则与限制

核心规则:围绕协调原子建模——每个聊天室/游戏/用户一个 DO,而非一个全局 DO;使用 getByName() 做确定性路由——相同输入对应相同 DO 实例;使用 SQLite 存储——在迁移中配置 new_sqlite_classes;在构造函数中初始化——仅对 schema 设置使用 blockConcurrencyWhile();使用 RPC 方法——而非 fetch() 处理器(兼容日期 >= 2024-04-03);先持久化后缓存——始终先写入存储再更新内存状态;每个 DO 一个闹钟——setAlarm() 会替换任何现有闹钟。

授权方面:Durable Objects 没有单独的角色或权限,访问权限跟随实现它们的 Worker。在授予可观测性或 Data Studio 访问权限前,应检索当前的 Durable Objects 授权指引,并将 Workers 角色限定到预期的 Worker 或 Workers 产品。

反模式(切勿使用):单个全局 DO 处理所有请求(瓶颈);在每个请求上使用 blockConcurrencyWhile()(扼杀吞吐量);仅在内存中存储关键状态(驱逐或崩溃时丢失);在相关存储写入之间使用 await(破坏原子性);在 fetch() 或外部 I/O 期间持有 blockConcurrencyWhile()。

测试方面:在配置测试套件或编写 Durable Object 测试前,应阅读测试参考,它指向当前设置、API 和示例,并标识需要覆盖的行为。