mcpField
D
durable-objects

durable-objects

github.com/cloudflare开发5.4k84 次安装今天更新
代码仓库

关于 durable-objects

用于使用 Cloudflare Durable Objects 构建和审查有状态应用的开发技能,涵盖协调、存储、RPC、定时任务、配置和测试,并提供实现参考资料。

主要功能

  1. 01Durable Object 设计指导
  2. 02存储、RPC 和定时任务模式
  3. 03Wrangler 绑定与迁移配置
  4. 04使用 Vitest pool for Workers 测试
  5. 05提供实现细节参考资料

适用场景

  1. 01构建聊天或游戏协调状态
  2. 02实现 Durable Object RPC 或定时任务
  3. 03配置绑定和迁移
  4. 04测试 Durable Object 代码

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cloudflare/cloudflare-docs --skill durable-objects

安装后在 Claude Code 中输入/durable-objects确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
rules.md
testing.md
workers.md

详细介绍

Durable Objects

使用 Durable Objects 在 Cloudflare 边缘构建有状态的协同应用。

检索优先开发

对于 Durable Objects 相关任务,优先检索官方文档,而非依赖预训练知识。

资源URL
文档https://developers.cloudflare.com/durable-objects/
API 参考https://developers.cloudflare.com/durable-objects/api/
最佳实践https://developers.cloudflare.com/durable-objects/best-practices/
示例https://developers.cloudflare.com/durable-objects/examples/

实现功能时,请获取相关文档页面。

适用场景

  • 为有状态协同创建新的 Durable Object 类
  • 实现 RPC 方法、定时任务或 WebSocket 处理程序
  • 根据最佳实践审查现有 DO 代码
  • 配置 wrangler.jsonc/toml 中的 DO 绑定和迁移
  • 使用 @cloudflare/vitest-pool-workers 编写测试
  • 设计分片策略以及父子关系

参考文档

  • ./references/rules.md - 核心规则、存储、并发、RPC、定时任务
  • ./references/testing.md - Vitest 设置、单元/集成测试、定时任务测试
  • ./references/workers.md - Workers 处理程序、类型、wrangler 配置、可观测性

搜索:blockConcurrencyWhile、idFromName、getByName、setAlarm、sql.exec

核心原则

适用 Durable Objects 的场景
需求示例
协同聊天室、多人游戏、协作文档
强一致性库存、预订系统、回合制游戏
按实体存储多租户 SaaS、用户数据
持久连接WebSocket、实时通知
按实体安排任务订阅续期、游戏超时
不适用的场景
  • 无状态请求处理(使用普通 Workers)
  • 需要最大程度的全球分布
  • 扇出量大且彼此独立的请求

快速参考

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 });
  },
};

关键规则

  1. 围绕协同单元建模 - 每个聊天室/游戏/用户对应一个 DO,而不是使用一个全局 DO
  2. 使用 getByName() 实现确定性路由 - 相同输入 = 相同 DO 实例
  3. 使用 SQLite 存储 - 在迁移中配置 new_sqlite_classes
  4. 在构造函数中初始化 - 仅使用 blockConcurrencyWhile() 设置架构
  5. 使用 RPC 方法 - 不使用 fetch() 处理程序(兼容性日期 >= 2024-04-03)
  6. 先持久化,再缓存 - 更新内存状态前,始终先写入存储
  7. 每个 DO 只能有一个定时任务 - setAlarm() 会替换任何现有定时任务

反模式(绝对不要)

  • 使用单个全局 DO 处理所有请求(会形成瓶颈)
  • 在每个请求上使用 blockConcurrencyWhile()(会严重降低吞吐量)
  • 仅在内存中存储关键状态(驱逐或崩溃时会丢失)
  • 在相关存储写入之间使用 await(会破坏原子性)
  • 在 fetch() 或外部 I/O 期间持有 blockConcurrencyWhile()

创建 Stub

// Deterministic - preferred for most cases
const stub = env.MY_DO.getByName("room-123");

// From existing ID string
const id = env.MY_DO.idFromString(storedIdString);
const stub = env.MY_DO.get(id);

// New unique ID - store mapping externally
const id = env.MY_DO.newUniqueId();
const stub = env.MY_DO.get(id);

存储操作

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

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

定时任务

// Schedule (replaces existing)
await this.ctx.storage.setAlarm(Date.now() + 60_000);

// Handler
async alarm(): Promise<void> {
  // Process scheduled work
  // Optionally reschedule: await this.ctx.storage.setAlarm(...)
}

// Cancel
await this.ctx.storage.deleteAlarm();

测试快速入门

import { env } from "cloudflare:test";
import { describe, it, expect } from "vitest";

describe("MyDO", () => {
  it("should work", async () => {
    const stub = env.MY_DO.getByName("test");
    const result = await stub.addItem("test");
    expect(result).toBe(1);
  });
});

评论

支持 Markdown