关于 rivetkit
rivetkit 是用于构建 Rivet Actors 的技能,面向需要长生命周期、有状态进程的后端开发者。它涵盖持久化状态、实时通信、工作流与 Actor 调试。
主要功能
- 01构建长生命周期有状态 Actor
- 02使用状态、KV 和 SQLite 持久化
- 03通过 WebSocket 广播实时事件
- 04使用队列处理持久消息
- 05通过 Inspector 检查运行中的 Actor
适用场景
- 01为 AI Agent 管理多步工具调用和会话记忆
- 02构建多人协作应用或实时聊天
- 03编排后台任务和持久队列
- 04检查 Actor 状态、连接和执行记录
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ pedronauck/ skills --skill rivetkit安装后在 Claude Code 中输入/rivetkit确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
index.jsonopenapi.jsonreference/actors/access-control.mdactions.mdai-and-user-generated-actors.mdappearance.mdauthentication.mdcommunicating-between-actors.mdconnections.mddebugging.mddesign-patterns.mddestroy.mdephemeral-variables.mderrors.mdevents.mdfetch-and-websocket-handler.mdhelper-types.mdhttp-api.mdinput.mdkeys.mdkv.mdlifecycle.mdlimits.mdmetadata.mdpostgres.mdqueues.mdreference/actors/quickstart/backend.mdcloudflare-workers.mdnext-js.mdreact.md详细介绍
Rivet Actors
在 Rivet 的 Actor 运行时上构建高性能、长生命周期的内存进程。当 HTTP 端点、数据库或队列无法再满足 AI Agent、实时协作、工作流编排或地理分布式数据的需求时,请使用此技能。
遇到问题时的处理方式
如果某些功能未按预期工作,或者你遇到困难,请提示用户加入 Rivet Discord,或在 Rivet GitHub 上提交 issue,以报告问题并获取帮助。
向用户提供一份预先生成的报告,包含:
- 症状
- 问题发生在本地开发环境、已部署环境,还是两者都有
- 你看到的错误
- 与此问题相关的源代码
- 你为解决问题尝试过的方法
- 环境
- RivetKit 版本
- 运行时(Node、Bun 等),包括版本
- 如适用,所用的服务提供商(例如 Vercel、Railway 等)
- 如适用,所用的 HTTP 路由器(例如 Hono、Express、Elysia)
调试 Actors
使用检查器 HTTP API 检查正在运行的 Actor。这些端点可通过网关访问,路径为 /gateway/{actor_id}/inspector/*。主要端点:
GET /inspector/summary- Actor 的完整快照(状态、连接、RPC、队列)GET /inspector/state/PATCH /inspector/state- 读取/写入 Actor 状态GET /inspector/connections- 活动连接GET /inspector/rpcs- 可用操作POST /inspector/action/{name}- 使用{"args": [...]}执行操作GET /inspector/queue?limit=50- 队列状态GET /inspector/traces?startMs=0&endMs=...&limit=1000- 跟踪跨度(OTLP JSON)GET /inspector/workflow-history- 工作流历史记录和状态
在本地开发环境中,无需身份验证令牌。在生产环境中,请传入 Authorization: Bearer <RIVET_INSPECTOR_TOKEN>。详情请参阅调试文档。
引用来源
提供 Rivet 文档中的信息时,请引用规范 URL,方便用户了解更多信息。每个参考文件的标头元数据中都包含其规范 URL。
引用方式:
- 对关键概念使用行内链接:“使用 Actor 键 唯一标识实例。”
- 对复杂主题的说明后添加“了解更多”链接
查找规范 URL:
下方的参考索引链接到参考文件。每个文件的标头都包含:
> Canonical URL: https://rivet.dev/docs/actors/actions
引用时请使用该规范 URL,而不是参考文件路径。
示例:
- 操作 →
https://rivet.dev/docs/actors/actions - React 客户端 →
https://rivet.dev/docs/clients/react - 在 Kubernetes 上自托管 →
https://rivet.dev/docs/self-hosting/kubernetes
入门步骤
- 安装 RivetKit(最新版本:2.1.0-rc.2)
npm install [email protected] - 使用
setup({ use: { /* actors */ } })定义注册表。 - 暴露
registry.serve()或registry.handler()(无服务器模式),或registry.startRunner()(Runner 模式)。除非用户有特定理由使用 Runner 模式,否则优先使用无服务器模式。 - 部署前确认
/api/rivet/metadata返回 200。 - 配置 Rivet Cloud 或自托管引擎
- 集成客户端(请参阅下方的 JavaScript、React 或 Swift 客户端指南)
- 询问用户是否要部署。如果要部署,请转到“部署 Rivet 后端”。
更多信息请阅读与用户项目相关的快速入门指南。
错误处理策略
- 默认优先采用快速失败行为。
- 除非确实需要进行错误恢复、清理,或添加可执行的上下文信息,否则避免使用
try/catch。 - 绝不要吞掉错误。如果添加
catch,必须明确处理错误,至少要记录错误日志。 - 无法恢复时,记录上下文并重新抛出错误。
State 与 Vars:持久化规则
c.vars 是临时的。 每次重启、崩溃、升级或休眠/唤醒周期后,c.vars 中的数据都会丢失。仅将 c.vars 用于不可序列化的对象(例如物理引擎、WebSocket 引用、事件发射器、缓存),或真正临时的运行时数据(例如断开连接后便无关紧要的当前输入方向)。
持久化存储选项。 任何必须在重启后保留的数据都应存放在以下选项之一,而不是 c.vars 中:
c.state— 用于规模小且有界的数据,可进行 CBOR 序列化。非常适合配置、计数器、小型玩家列表、阶段标志等。请控制在 128 KB 以内。不要在此存储无界或不断增长的数据(例如聊天记录、事件历史、无限增长的已生成实体列表)。每个持久化周期都会将 State 作为单个数据块读取/写入。c.kv— 用于无界数据的键值存储。c.state的底层就是使用它。支持二进制值。适用于较大或大小不定的数据,例如用户物品栏、世界区块、文件数据块,或任何可能随时间增长的集合。键的作用域限定在 Actor 实例内。c.db— 用于结构化或复杂数据的 SQLite 数据库。当你需要查询、索引、联接、聚合或关系建模时使用。非常适合排行榜、对战历史、玩家池,或任何能从 SQL 中受益的数据。
常见错误: 将有意义的游戏/应用数据存入 c.vars,而不是进行持久化。例如,如果用户可以在物理模拟中生成对象,那么生成定义(位置、大小、类型)必须持久化到 c.state(如果数据无界,则存入 c.kv),即使物理引擎等(不可序列化的)运行时对象存放在 c.vars 中也是如此。重启后,run() 应根据持久化数据重新创建运行时对象。
部署 Rivet 后端
除非另有说明,否则假定用户要部署到 Rivet Cloud。如果用户选择自行托管,请参阅下方的自托管指南。
- 确认 Rivet Actors 在本地开发环境中正常运行
- 提示用户选择要部署到的提供商(提供商列表请参阅 连接,例如 Vercel、Railway 等)
- 按照相应提供商的部署指南操作。需要手动干预时,应指导用户完成。
API 参考
RivetKit OpenAPI 规范位于技能目录中的 openapi.json 文件。该文件记录了用于管理 Actors 的所有 HTTP 端点。
其他说明
- Rivet 的域名是 rivet.dev,而不是 rivet.gg
功能
- 长生命周期、有状态计算:每个计算单元都像一台能在请求之间记住信息的小型服务——无需重新从数据库获取数据,也不必担心超时。类似 AWS Lambda,但带有内存且不会超时。
- 极速读写:State 存储在与计算相同的机器上,因此读写速度极快。无需往返数据库,也没有延迟峰值。State 会持久化到 Rivet,以便长期存储,因此服务器重启后仍会保留。
- 实时:通过 WebSocket 实时更新 State 并广播变更。无需外部发布/订阅系统,也无需轮询——直接使用内置的低延迟事件。
- 无限扩展:自动从零扩展到数百万个并发 Actor。按实际用量付费,支持即时扩缩容且没有冷启动。
- 容错:内置错误处理与恢复机制。Actor 会在发生故障时自动重启,同时保持 State 完整性并继续运行。
何时使用 Rivet Actors
- AI Agent 与沙箱:多步骤工具链、对话记忆、沙箱编排。
- 多人或协作应用:CRDT 文档、共享光标、实时仪表板、聊天。
- 工作流自动化:后台任务、cron、速率限制器、持久化队列、背压控制。
- 数据密集型后端:地理分布式或按租户划分的数据库、内存缓存、分片 SQL。
- 网络工作负载:WebSocket 服务、自定义协议、本地优先同步、边缘扇出。
最小项目
后端
actors.ts
import { actor, event, setup } from "rivetkit";
const counter = actor({
state: { count: 0 },
events: {
count: event<number>(),
},
actions: {
increment: (c, amount: number) => {
c.state.count += amount;
c.broadcast("count", c.state.count);
return c.state.count;
},
},
});
export const registry = setup({
use: { counter },
});
server.ts
如果适用,请集成到用户现有的服务中。否则,默认使用 Hono。
无框架
import { registry } from "./actors";
export default registry.serve();
Hono
import { Hono } from "hono";
import { registry } from "./actors";
const app = new Hono();
app.all("/api/rivet/*", (c) => registry.handler(c.req.raw));
export default app;
Elysia
import { Elysia } from "elysia";
import { registry } from "./actors";
const app = new Elysia()
.all("/api/rivet/*", (c) => registry.handler(c.request));
export default app;
客户端文档
使用与你的应用匹配的客户端 SDK:
Actor 速查
内存状态
重启、崩溃和部署后仍会保留的持久数据。状态会持久化到 Rivet Cloud 或 Rivet 可自托管服务中,因此即使当前进程崩溃或退出,数据也会保留。
静态初始状态
import { actor } from "rivetkit";
const counter = actor({
state: { count: 0 },
actions: {
increment: (c) => c.state.count += 1,
},
});
动态初始状态
import { actor } from "rivetkit";
interface CounterState {
count: number;
}
const counter = actor({
state: { count: 0 } as CounterState,
createState: (c, input: { start?: number }): CounterState => ({
count: input.start ?? 0,
}),
actions: {
increment: (c) => c.state.count += 1,
},
});
键
键用于唯一标识 Actor 实例。使用复合键(数组)进行分层寻址:
import { actor, setup } from "rivetkit";
import { createClient } from "rivetkit/client";
const chatRoom = actor({
state: { messages: [] as string[] },
actions: {
getRoomInfo: (c) => ({ org: c.key[0], room: c.key[1] }),
},
});
const registry = setup({ use: { chatRoom } });
const client = createClient<typeof registry>();
// Compound key: [org, room]
client.chatRoom.getOrCreate(["org-acme", "general"]);
// Access key inside actor via c.key
当 userId 包含用户数据时,不要使用字符串插值(如 "org:${userId}")构建键。请改用数组,以防止键注入攻击。
输入
创建 Actor 时传入初始化数据。
import { actor, setup } from "rivetkit";
import { createClient } from "rivetkit/client";
const game = actor({
createState: (c, input: { mode: string }) => ({ mode: input.mode }),
actions: {},
});
const registry = setup({ use: { game } });
const client = createClient<typeof registry>();
// Client usage
const gameHandle = client.game.getOrCreate(["game-1"], {
createWithInput: { mode: "ranked" }
});
临时变量
重启后不会保留的临时数据。用于存放不可序列化的对象(事件发射器、连接等)。
静态初始变量
import { actor } from "rivetkit";
const counter = actor({
state: { count: 0 },
vars: { lastAccess: 0 },
actions: {
increment: (c) => {
c.vars.lastAccess = Date.now();
return c.state.count += 1;
},
},
});
动态初始变量
import { actor } from "rivetkit";
const counter = actor({
state: { count: 0 },
createVars: () => ({
emitter: new EventTarget(),
}),
actions: {
increment: (c) => {
c.vars.emitter.dispatchEvent(new Event("change"));
return c.state.count += 1;
},
},
});
操作
操作是客户端和其他 Actor 与某个 Actor 通信的主要方式。
import { actor } from "rivetkit";
const counter = actor({
state: { count: 0 },
actions: {
increment: (c, amount: number) => (c.state.count += amount),
getCount: (c) => c.state.count,
},
});
事件与广播
事件支持 Actor 与已连接客户端之间的实时通信。
import { actor, event } from "rivetkit";
const chatRoom = actor({
state: { messages: [] as string[] },
events: {
newMessage: event<{ text: string }>(),
},
actions: {
sendMessage: (c, text: string) => {
// Broadcast to ALL connected clients
c.broadcast("newMessage", { text });
},
},
});
连接
通过 c.conn 访问当前连接,或通过 c.conns 访问所有已连接的客户端。使用 c.conn.id 或 c.conn.state 安全地识别调用操作的对象。连接状态通过 connState 或 createConnState 初始化;它们会接收客户端连接时传入的参数。
静态连接初始状态
import { actor } from "rivetkit";
const chatRoom = actor({
state: {},
connState: { visitorId: 0 },
onConnect: (c, conn) => {
conn.state.visitorId = Math.random();
},
actions: {
whoAmI: (c) => c.conn.state.visitorId,
},
});
动态连接初始状态
import { actor } from "rivetkit";
const chatRoom = actor({
state: {},
// params passed from client
createConnState: (c, params: { userId: string }) => ({
userId: params.userId,
}),
actions: {
// Access current connection's state and params
whoAmI: (c) => ({
state: c.conn.state,
params: c.conn.params,
}),
// Iterate all connections with c.conns
notifyOthers: (c, text: string) => {
for (const conn of c.conns.values()) {
if (conn !== c.conn) conn.send("notification", { text });
}
},
},
});
队列
使用队列在 run 循环中按顺序处理持久消息。
import { actor, queue } from "rivetkit";
const counter = actor({
state: { value: 0 },
queues: {
increment: queue<{ amount: number }>(),
},
run: async (c) => {
for await (const message of c.queue.iter()) {
c.state.value += message.body.amount;
}
},
});
工作流
当 run 逻辑需要可持久化、可重放的多步骤执行时,请使用工作流。
import { actor, queue } from "rivetkit";
import { workflow } from "rivetkit/workflow";
const worker = actor({
state: { processed: 0 },
queues: {
tasks: queue<{ url: string }>(),
},
run: workflow(async (ctx) => {
await ctx.loop("task-loop", async (loopCtx) => {
const message = await loopCtx.queue.next("wait-task");
await loopCtx.step("process-task", async () => {
await processTask(message.body.url);
loopCtx.state.processed += 1;
});
});
}),
});
async function processTask(url: string): Promise<void> {
const res = await fetch(url, { method: "POST" });
if (!res.ok) throw new Error(`Task failed: ${res.status}`);
}
Actor 间通信
Actor 可以使用 c.client() 调用其他 Actor。
import { actor, setup } from "rivetkit";
const inventory = actor({
state: { stock: 100 },
actions: {
reserve: (c, amount: number) => { c.state.stock -= amount; }
}
});
const order = actor({
state: {},
actions: {
process: async (c) => {
const client = c.client<typeof registry>();
await client.inventory.getOrCreate(["main"]).reserve(1);
},
},
});
const registry = setup({ use: { inventory, order } });
调度
安排操作在延迟后或指定时间运行。调度会在重启、升级和崩溃后保留。
import { actor, event } from "rivetkit";
const reminder = actor({
state: { message: "" },
events: {
reminder: event<{ message: string }>(),
},
actions: {
// Schedule action to run after delay (ms)
setReminder: (c, message: string, delayMs: number) => {
c.state.message = message;
c.schedule.after(delayMs, "sendReminder");
},
// Schedule action to run at specific timestamp
setReminderAt: (c, message: string, timestamp: number) => {
c.state.message = message;
c.schedule.at(timestamp, "sendReminder");
},
sendReminder: (c) => {
c.broadcast("reminder", { message: c.state.message });
},
},
});
销毁 Actor
使用 c.destroy() 永久删除 Actor 及其状态。
import { actor } from "rivetkit";
const userAccount = actor({
state: { email: "", name: "" },
onDestroy: (c) => {
console.log(`Account ${c.state.email} deleted`);
},
actions: {
deleteAccount: (c) => {
c.destroy();
},
},
});
生命周期钩子
Actor 支持用于初始化、后台处理、连接、网络和状态变更的钩子。使用 run 执行长期后台循环,并通过 c.aborted 或 c.abortSignal 在关闭时正常退出。
import { actor, event, queue } from "rivetkit";
interface RoomState {
users: Record<string, boolean>;
name?: string;
}
interface RoomInput {
roomName: string;
}
interface ConnState {
userId: string;
joinedAt: number;
}
const chatRoom = actor({
state: { users: {} } as RoomState,
vars: { startTime: 0 },
connState: { userId: "", joinedAt: 0 } as ConnState,
events: {
stateChanged: event<RoomState>(),
},
queues: {
work: queue<{ task: string }>(),
},
// State & vars initialization
createState: (c, input: RoomInput): RoomState => ({ users: {}, name: input.roomName }),
createVars: () => ({ startTime: Date.now() }),
// Actor lifecycle
onCreate: (c) => console.log("created", c.key),
onDestroy: (c) => console.log("destroyed"),
onWake: (c) => console.log("actor started"),
onSleep: (c) => console.log("actor sleeping"),
run: async (c) => {
for await (const message of c.queue.iter()) {
console.log("processing", message.body.task);
}
},
onStateChange: (c, newState) => c.broadcast("stateChanged", newState),
// Connection lifecycle
createConnState: (c, params): ConnState => ({ userId: (params as { userId: string }).userId, joinedAt: Date.now() }),
onBeforeConnect: (c, params) => { /* validate auth */ },
onConnect: (c, conn) => console.log("connected:", conn.state.userId),
onDisconnect: (c, conn) => console.log("disconnected:", conn.state.userId),
// Networking
onRequest: (c, req) => new Response(JSON.stringify(c.state)),
onWebSocket: (c, socket) => socket.addEventListener("message", console.log),
// Response transformation
onBeforeActionResponse: <Out>(c: unknown, name: string, args: unknown[], output: Out): Out => output,
actions: {},
});
上下文类型
在 Actor 定义外编写辅助函数时,使用 *ContextOf<typeof myActor> 提取正确的上下文类型。不要手动定义自己的上下文接口——始终从 Actor 定义派生。
import { actor, ActionContextOf } from "rivetkit";
const gameRoom = actor({
state: { players: [] as string[], score: 0 },
actions: {
addPlayer: (c, playerId: string) => {
validatePlayer(c, playerId);
c.state.players.push(playerId);
},
},
});
// Good: derive context type from actor definition
function validatePlayer(c: ActionContextOf<typeof gameRoom>, playerId: string) {
if (c.state.players.includes(playerId)) {
throw new Error("Player already in room");
}
}
// Bad: don't manually define context types like this
// type MyContext = { state: { players: string[] }; ... };
错误
使用 UserError 抛出可安全返回给客户端的错误。传入 metadata 可包含结构化数据。出于安全考虑,其他错误会转换为通用的“内部错误”。
Actor
import { actor, UserError } from "rivetkit";
const user = actor({
state: { username: "" },
actions: {
updateUsername: (c, username: string) => {
if (username.length < 3) {
throw new UserError("Username too short", {
code: "username_too_short",
metadata: { minLength: 3, actual: username.length },
});
}
c.state.username = username;
},
},
});
客户端
import { actor, setup } from "rivetkit";
import { createClient, ActorError } from "rivetkit/client";
const user = actor({
state: { username: "" },
actions: { updateUsername: (c, username: string) => { c.state.username = username; } }
});
const registry = setup({ use: { user } });
const client = createClient<typeof registry>();
try {
await client.user.getOrCreate([]).updateUsername("ab");
} catch (error) {
if (error instanceof ActorError) {
console.log(error.code); // "username_too_short"
console.log(error.metadata); // { minLength: 3, actual: 2 }
}
}
低级 HTTP 与 WebSocket 处理程序
对于自定义协议,或需要直接访问 HTTP Request/Response 或 WebSocket 连接的集成库,请使用 onRequest 和 onWebSocket。
HTTP 处理程序文档 · WebSocket 处理程序文档
图标与名称
通过显示名称和图标自定义 Actor 在 UI 中的显示方式。建议始终为 Actor 提供名称和图标,以便在仪表板中更轻松地区分它们。
import { actor } from "rivetkit";
const chatRoom = actor({
options: {
name: "Chat Room",
icon: "💬", // or FontAwesome: "comments", "chart-line", etc.
},
// ...
});
客户端文档
在此查阅完整的客户端指南:
常见模式
Actor 通过隔离状态和消息传递自然扩展。使用以下模式构建应用程序:
每个实体一个 Actor
为每个用户、文档或房间创建一个 Actor。使用复合键限定实体范围:
import { createClient } from "rivetkit/client";
import type { registry } from "./actors";
const client = createClient<typeof registry>();
// Single key: one actor per user
client.user.getOrCreate(["user-123"]);
// Compound key: document scoped to an organization
client.document.getOrCreate(["org-acme", "doc-456"]);
import { actor, setup } from "rivetkit";
export const user = actor({
state: { name: "" },
actions: {},
});
export const document = actor({
state: { content: "" },
actions: {},
});
export const registry = setup({ use: { user, document } });
协调器与数据 Actor
数据 Actor 负责处理核心逻辑(聊天室、游戏会话、用户数据)。协调器 Actor 跟踪并管理数据 Actor 集合——可以将它们视为索引。
import { actor, setup } from "rivetkit";
// Coordinator: tracks chat rooms within an organization
export const chatRoomList = actor({
state: { rooms: [] as string[] },
actions: {
addRoom: async (c, name: string) => {
// Create the chat room actor
const client = c.client<typeof registry>();
await client.chatRoom.create([c.key[0], name]);
c.state.rooms.push(name);
},
listRooms: (c) => c.state.rooms,
},
});
// Data actor: handles a single chat room
export const chatRoom = actor({
state: { messages: [] as string[] },
actions: {
send: (c, msg: string) => { c.state.messages.push(msg); },
},
});
export const registry = setup({ use: { chatRoomList, chatRoom } });
import { createClient } from "rivetkit/client";
import type { registry } from "./actors";
const client = createClient<typeof registry>();
// Coordinator per org
const coordinator = client.chatRoomList.getOrCreate(["org-acme"]);
await coordinator.addRoom("general");
await coordinator.addRoom("random");
// Access chat rooms created by coordinator
client.chatRoom.get(["org-acme", "general"]);
运行循环
在 Actor 内使用 run 循环执行持续的后台工作。按顺序处理队列消息、定期运行逻辑、流式传输 AI 响应,或协调长时间运行的任务。
import { actor, queue, setup } from "rivetkit";
const counterWorker = actor({
state: { value: 0 },
queues: {
mutate: queue<{ delta: number }>(),
},
run: async (c) => {
for await (const message of c.queue.iter()) {
c.state.value += message.body.delta;
}
},
actions: {
getValue: (c) => c.state.value,
},
});
const registry = setup({ use: { counterWorker } });
工作流循环
对于长期运行、持久化的工作流,请使用此模式:初始化资源、循环处理命令,然后进行清理。
import { actor, queue, setup } from "rivetkit";
import { Loop, workflow } from "rivetkit/workflow";
type WorkMessage = { amount: number };
type ControlMessage = { type: "stop"; reason: string };
const worker = actor({
state: {
phase: "idle" as "idle" | "running" | "stopped",
processed: 0,
total: 0,
stopReason: null as string | null,
},
queues: {
work: queue<WorkMessage>(),
control: queue<ControlMessage>(),
},
run: workflow(async (ctx) => {
await ctx.step("setup", async () => {
await fetch("https://api.example.com/workers/init", { method: "POST" });
ctx.state.phase = "running";
ctx.state.stopReason = null;
});
const stopReason = await ctx.loop("worker-loop", async (loopCtx) => {
const message = await loopCtx.queue.next("wait-command", {
names: ["work", "control"],
});
if (message.name === "work") {
await loopCtx.step("apply-work", async () => {
await fetch("https://api.example.com/workers/process", {
method: "POST",
body: JSON.stringify({ amount: message.body.amount }),
});
loopCtx.state.processed += 1;
loopCtx.state.total += message.body.amount;
});
return;
}
return Loop.break((message.body as ControlMessage).reason);
});
await ctx.step("teardown", async () => {
await fetch("https://api.example.com/workers/shutdown", { method: "POST" });
ctx.state.phase = "stopped";
ctx.state.stopReason = stopReason;
});
}),
});
const registry = setup({ use: { worker } });
操作与队列
- 操作不具备持久性。将它们用于实时读取、临时数据以及玩家输入等低延迟通信。
- 队列具备持久性。使用它们通过运行循环串行处理变更,避免与 SQLite 和其他本地状态发生竞态条件。调用方仍可等待队列任务的响应。
身份验证、安全与 CORS
- 在
onBeforeConnect或createConnState中验证凭据,并抛出错误以拒绝未授权的连接。 - 在操作中使用
c.conn.state安全地识别用户,而不要信任操作参数。 - 对于跨域访问,请在
onBeforeConnect中验证请求来源。
版本与升级
部署新代码时,请设置版本号,以便 Rivet 将新 Actor 路由到最新的运行器,并可选择排空旧运行器。版本可使用构建时间戳、git 提交计数或 CI 构建编号。
反模式
切勿构建“全能” Actor
不要将所有逻辑都放在单个 Actor 中。全能 Actor 会让每个操作都经过同一个瓶颈,扼杀并行性,并导致整个系统作为一个整体发生故障。应按实体拆分为职责明确的 Actor。
切勿为每个请求创建一个 Actor
Actor 的生命周期较长,并会在请求之间维护状态。为每个传入请求创建新的 Actor 会舍弃该模型的核心优势,并将资源浪费在 Actor 的创建和销毁上。应使用 Actor 管理持久实体,并使用常规函数处理无状态工作。
参考索引
Actors
- 访问控制
- 操作
- Actor 密钥
- Actor 调度
- AI 和用户生成的 Rivet Actor
- 身份验证
- Cloudflare Workers 快速入门
- Actor 之间的通信
- 连接
- 调试
- 设计模式
- 销毁 Actor
- 临时变量
- 错误
- 外部 SQL 数据库
- Fetch 和 WebSocket 处理程序
- 辅助类型
- 图标和名称
- 内存状态
- 输入参数
- 生命周期
- 限制
- 底层 HTTP 请求处理程序
- 底层 KV 存储
- 底层 WebSocket 处理程序
- 元数据
- Next.js 快速入门
- Node.js 和 Bun 快速入门
- 队列和运行循环
- React 快速入门
- 实时功能
- 扩展和并发
- 共享和加入状态
- SQLite
- SQLite + Drizzle
- 测试
- 类型
- 原生 HTTP API
- 版本和升级
- 工作流
客户端
连接
- 部署到 Amazon Web Services Lambda
- 部署到 AWS ECS
- 部署到 Cloudflare Workers
- 部署到 Freestyle
- 部署到 Google Cloud Run
- 部署到 Hetzner
- 部署到 Kubernetes
- 部署到 Railway
- 部署到 Vercel
- 部署到 VM 和裸金属服务器
- Supabase