尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Rivet Actors 实时聊天室实战:Actor 状态管理、事件广播与多房间隔离完整实现
Rivet Actors 实时聊天室实战Actor 状态管理、事件广播与多房间隔离完整实现【免费下载链接】actorsRivet Actors are the primitive for stateful workloads. Built for AI agents, collaborative apps, and durable execution.项目地址: https://gitcode.com/GitHub_Trending/riv/actors实时聊天室是验证有状态工作负载能力的典型场景需要瞬时把消息推送给所有在线客户端需要让历史记录在进程重启后依然完整还需要让不同房间的数据互不干扰。仓库中的 examples/chat-room 示例项目正是用 Rivet Actors 把这些诉求落地的完整参考实现。本文以此项目为主体结合仓库内 RivetKit SDK 的源码与测试逐层拆解 Actor 定义、SQLite 持久化、事件广播、客户端接入与测试验证的完整链路帮助你把同样的模式迁移到自己的协作类应用中。项目全景一个聊天室由哪些部分组成先看 examples/chat-room 的目录结构理解一个 Actor 示例项目的完整形态examples/chat-room/ ├── src/ │ └── index.ts # 服务端Actor 定义 registry 注册 服务启动 ├── frontend/ │ ├── App.tsx # React 前端useActor useEvent 实时订阅 │ └── main.tsx # React 入口 ├── tests/ │ └── chat-room.test.ts # vitest 集成测试 ├── package.json # dev / test / build 脚本与依赖 ├── vite.config.ts # 开发代理/actors、/metadata、/health ├── vitest.config.ts ├── tsconfig.json ├── turbo.json # 依赖 rivetkit/react、rivetkit 的构建顺序 ├── Dockerfile # 多阶段镜像构建server static 资源 ├── index.html └── README.md整个项目只有一份服务端入口 src/index.ts其余是前端与工程化配置。它的数据流模型非常简洁客户端通过 React 的createRivetKit建立与 Actor 服务器的连接Action是客户端可远程调用的函数负责写入状态如sendMessageEvent是服务端向所有已连接客户端主动推送的广播如newMessageSQLite DB是 Actor 的持久化存储保证历史消息在重启后不丢失。这一「Action 写入 Event 广播 DB 持久化」的三段式模型正是 Rivet Actors 处理有状态实时交互的核心范式也贯穿本文后续所有小节。快速启动五分钟跑起聊天室根据 examples/chat-room/README.md 的说明本项目使用concurrently同时启动服务端与前端git clone https://github.com/rivet-dev/rivet.git cd rivet/examples/chat-room npm install npm run dev对应到仓库中 examples/chat-room/package.json 的脚本定义{ name: chat-room, version: 2.0.21, type: module, scripts: { dev: concurrently -n server,vite \tsx --watch src/index.ts\ \vite\, dev:server: tsx --watch src/index.ts, check-types: tsc --noEmit, test: vitest run, build: vite build, start: tsx src/index.ts }, dependencies: { rivetkit/react: workspace:*, react: ^18.2.0, react-dom: ^18.2.0, rivetkit: workspace:* } }脚本含义如下npm run dev用tsx --watch热重载服务端同时启动 Vite 开发服务器日志以server/vite两个前缀区分npm run dev:server只启动 Actor 服务端适合调试后端逻辑npm run test运行 vitest 集成测试见后文「测试验证」小节npm run build构建前端静态资源npm run start以生产方式运行服务端。启动后Actor 服务器监听在http://localhost:6420端口由 src/index.ts 中registry.start()与 frontend/App.tsx 中createRivetKit(http://localhost:6420)共同约定。开发期的跨域与 WebSocket 代理由 vite.config.ts 处理server: { clearScreen: false, proxy: { /actors: { target: http://localhost:6420, ws: true }, /metadata: { target: http://localhost:6420 }, /health: { target: http://localhost:6420 }, }, },其中/actors走 WebSocketws: true——这正是实时事件推送的通道/metadata与/health是 HTTP 端点分别用于获取 Actor 元信息与健康检查。若在仓库中直接使用注意rivetkit与rivetkit/react采用workspace:*工作区依赖需在仓库根目录执行pnpm install建立 workspace 链接后再运行示例。服务端实现用 actor() 定义有状态消息实体聊天室的服务端全部逻辑集中在 src/index.ts它展示了 Rivet Actors 三个最核心的抽象db持久化、events广播、actions远程调用。消息类型与 SQLite 持久化db首先定义一个消息的数据结构并给 Actor 挂上一个 SQLite 数据库用它来持久化聊天记录import { actor, event, setup } from rivetkit; import { db } from rivetkit/db; export type Message { sender: string; text: string; timestamp: number }; export const chatRoom actor({ // Persist chat history in the actors SQLite database db: db({ onMigrate: async (db) { await db.execute( CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, sender TEXT NOT NULL, text TEXT NOT NULL, timestamp INTEGER NOT NULL ) ); }, }), // ... });要点拆解db({ onMigrate })为 Actor 声明一个内置 SQLite 数据库onMigrate在 Actor 首次初始化时执行负责建表等迁移逻辑。这里创建了messages表id自增主键sender/text为消息内容timestamp为毫秒级时间戳该表保存在 Actor 自己的持久化存储中因此即使 Actor 实例休眠或重启聊天历史也能恢复——这是「Persistent chat history」特性的底层来源在 rivetkit-typescript/packages/rivetkit/src/actor/definition.ts 中可以看到actor()定义的完整形态BaseActorDefinition携带config内部通过flattenActionHandlers、flattenActionInputSchemas等工具把actions/events/db等配置归一化最终由setup()注册为可寻址的 Actor 类型。事件广播events服务端主动推送给客户端事件是「客户端被实时通知」的关键机制声明方式与使用方式如下events: { newMessage: eventMessage(), },在sendMessage中通过c.broadcast(newMessage, message)把新消息推送给所有已连接的客户端。每个事件声明为强类型eventMessage()让广播内容与前端订阅回调的类型完全对齐编译期即可校验负载结构避免手写字符串协议带来的类型漂移。动作actions客户端可远程调用的函数actions是客户端可以直接跨网络调用的函数聊天室定义了两个核心动作actions: { sendMessage: async (c, sender: string, text: string) { const message: Message { sender, text, timestamp: Date.now() }; await c.db.execute( INSERT INTO messages (sender, text, timestamp) VALUES (?, ?, ?), sender, text, message.timestamp, ); // Send events to all connected clients c.broadcast(newMessage, message); return message; }, getHistory: async (c) { const rows await c.db.execute( SELECT sender, text, timestamp FROM messages ORDER BY id ASC, ); return rows as Message[]; }, },sendMessage(sender, text)先写入 SQLite再通过c.broadcast(newMessage, message)广播最后把消息对象返回给调用方。注意写入与广播的顺序——先落库、后广播保证任何重放或重连后客户端拉取到的历史与实时流是一致的getHistory()按id ASC读出全部消息作为新客户端加入时的「初始历史」。前端在建立连接后首先调用它渲染历史再用useEvent增量追加新消息二者配合实现无缝的聊天记录加载。注册与启动setup start最后把 Actor 注册进 registry 并启动服务export const registry setup({ use: { chatRoom }, }); // Start the server on port 6420 registry.start();setup({ use: { chatRoom } })声明该服务器对外暴露的 Actor 类型集合export它以便前端createRivetKittypeof registry与测试setupTest(ctx, registry)复用同一份类型与运行时registry.start()启动 HTTP WebSocket 服务默认端口 6420。前端实现useActor 订阅实时消息流前端是纯 React入口在 frontend/main.tsx业务逻辑在 frontend/App.tsx。建立类型安全的连接import { createRivetKit } from rivetkit/react; import type { Message, registry } from ../src/index.ts; const { useActor } createRivetKittypeof registry(http://localhost:6420);createRivetKittypeof registry直接把服务端registry的类型带到前端此后useActor({ name: chatRoom, ... })返回的connection上会自动推导出sendMessage、getHistory的签名与newMessage事件的负载类型。前后端共享同一份类型定义是这种架构在大型协作项目中最有价值的收益。接入 Actor 与实时事件export function App() { const [roomId, setRoomId] useState(general); const [username, setUsername] useState(User); const [input, setInput] useState(); const [messages, setMessages] useStateMessage[]([]); const chatRoom useActor({ name: chatRoom, key: [roomId], }); useEffect(() { if (chatRoom.connection) { chatRoom.connection.getHistory().then(setMessages); } }, [chatRoom.connection]); chatRoom.useEvent(newMessage, (message: Message) { setMessages((prev) [...prev, message]); }); // ... }两个关键 Hook 的行为useActor({ name: chatRoom, key: [roomId] })按key定位/创建 Actor 实例并建立连接key变化如切换房间名会重建连接。返回的connection是已连通的 RPC 句柄未连通时为nulluseEvent(newMessage, handler)订阅服务端广播收到新消息后以函数式setMessages增量追加天然避免闭包捕获过期状态的问题。发送消息与界面渲染const sendMessage async () { if (chatRoom.connection input.trim()) { await chatRoom.connection.sendMessage(username, input); setInput(); } };界面层把消息按sender/text/timestamp渲染时间戳通过new Date(msg.timestamp).toLocaleTimeString()本地化展示输入框与发送按钮在connection尚未建立时处于disabled状态防止连接未就绪时的无效调用。这套「连接状态驱动 UI 可用性」的处理方式同样适用于生产级协作应用。多房间隔离key 驱动的 Actor 实例模型README 明确指出「Multiple chat rooms: Each room is a separate actor instance with isolated state」。这个特性的实现机制在前端调用中可见一斑const chatRoom useActor({ name: chatRoom, key: [roomId], });name是 Actor 类型key是同一类型下的实例标识name key共同决定一个唯一的 Actor 实例不同roomId如general、design会解析到不同的 Actor 实例每个实例拥有自己独立的 SQLite 数据库与事件连接集合——这就是「隔离状态」的来源房间 A 的消息不会出现在房间 B 的历史里房间 A 的广播也只到达房间 A 的客户端同一roomId的多个客户端连接到同一个实例因此能共享同一份messages表并同时收到newMessage广播。测试中也印证了这一点client.chatRoom.getOrCreate([test-room])与getOrCreate([test-timestamps])使用不同的 key得到的是相互独立的实例详见 tests/chat-room.test.ts。这种「一个逻辑实体 一个 Actor 实例」的映射是 Rivet Actors 相对传统无状态服务的关键差异状态归属清晰、天然支持按 key 的水平切分。测试验证用 vitest 覆盖核心行为examples/chat-room/tests/chat-room.test.ts 通过rivetkit/test的setupTest启动 Actor 运行时进行集成测试覆盖了聊天室的核心契约import { setupTest } from rivetkit/test; import { expect, test } from vitest; import { registry } from ../src/index.ts; test(Chat room can handle message sending and history, async (ctx) { const { client } await setupTest(ctx, registry); const room client.chatRoom.getOrCreate([test-room]); // Test initial state const initialHistory await room.getHistory(); expect(initialHistory).toEqual([]); // Send a message const message1 await room.sendMessage(Alice, Hello everyone!); expect(message1).toMatchObject({ sender: Alice, text: Hello everyone!, timestamp: expect.any(Number), }); // Send another message, verify order const message2 await room.sendMessage(Bob, Hi Alice!); const history await room.getHistory(); expect(history).toHaveLength(2); expect(history[0]).toEqual(message1); expect(history[1]).toEqual(message2); });这套测试还覆盖了另外三个行为维度时间戳单调递增连续发送三条消息断言message2.timestamp message1.timestamp并遍历历史保证整体有序多用户支持Alice / Bob / Charlie 交替发言后历史长度为 4且sender与text顺序与发送顺序完全一致空消息边界发送空字符串也能正常落库并返回text为空、timestamp 0说明动作层对参数没有隐式的非空校验边界行为明确。这些断言直接验证了 README 中「Real-time messaging」「Persistent chat history」「Multiple chat rooms」三个核心特性的可测试性也为你在自己的 Actor 上添加测试提供了模板setupTest(ctx, registry)返回一个类型安全的clientclient.actorName.getOrCreate([key])即得到一个可调用的 Actor 句柄。容器化部署多阶段构建与静态托管examples/chat-room/Dockerfile 提供了把「Actor 服务器 前端静态资源」打包进一个镜像的参考做法# Build stage FROM node:22-alpine AS builder WORKDIR /app RUN corepack enable corepack prepare pnpmlatest --activate COPY package.json ./ RUN pnpm install --frozen-lockfilefalse COPY . . RUN pnpm run build # Runtime stage FROM node:22-alpine AS runtime WORKDIR /app RUN corepack enable corepack prepare pnpmlatest --activate COPY package.json ./ RUN pnpm install --prod --frozen-lockfilefalse COPY --frombuilder /app/dist ./dist COPY --frombuilder /app/public ./dist/public EXPOSE 8080 ENV PORT8080 ENV NODE_ENVproduction CMD [node_modules/.bin/srvx, dist/server.js]关键点多阶段构建builder 阶段安装完整依赖含 devDependencies并执行pnpm run buildruntime 阶段只安装生产依赖并复制构建产物dist与前端静态资源public镜像体积更小启动方式用srvx同时托管dist/server.jsActor 服务器与dist/public前端静态文件对外暴露 8080 端口生产环境只需一个容器工作目录约定注释指出srvx的--static路径相对 CWD/app解析因此public/映射到/app/public/构建时须保证静态资源输出到该位置。需要说明的是本示例以npm脚本作为开发入口Docker 采用pnpm安装依赖两者在 package.json 与 Dockerfile 中并存是示例仓库的既有配置直接照搬时请按你的包管理器选择其一。总结把聊天室模式迁移到你的有状态应用从 examples/chat-room 可以提炼出一套可复用的 Actor 应用骨架需求Rivet Actors 对应能力本示例中的体现实时推送eventsc.broadcastnewMessage事件广播历史持久化db SQLite 迁移messages表与onMigrate多租户/多房间隔离actor({ name, key })实例模型房间名作为 key客户端远程调用actionssendMessage/getHistory类型安全全链路typeof registry共享类型createRivetKittypeof registry自动化验证setupTest vitest顺序、时间戳、多用户、空消息用例把「房间」换成「会话」「租户」「文档」「游戏对局」中的任意一个把messages表换成对应的业务表就能得到一套具备实时协作、持久化与隔离能力的有状态服务。仓库中的 docs/actors 文档体系actions / state / events / sqlite 等主题可作为继续深入每一层能力的阅读入口而 rivetkit-typescript/packages/rivetkit 下的 SDK 源码则是验证行为细节的第一手资料。【免费下载链接】actorsRivet Actors are the primitive for stateful workloads. Built for AI agents, collaborative apps, and durable execution.项目地址: https://gitcode.com/GitHub_Trending/riv/actors创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

GEO技术如何重塑商业生态与竞争格局

GEO技术如何重塑商业生态与竞争格局

1. 项目概述"生态博弈与未来前瞻:GEO将如何重塑互联网、商业与竞争格局"这个标题揭示了当前数字经济发展中的一个关键趋势——地理空间数据(GEO)正在成为重塑商业生态系统的核心要素。作为一名长期观察数字经济发展的从业者,我见证了GEO技术从…

📅 2026/9/18 9:59:56
PostHog ReviewHog 验证器模型评估:Sonnet 5 @ xhigh 评分表深度解读——“全量保留“背后的 50% 精确率

PostHog ReviewHog 验证器模型评估:Sonnet 5 @ xhigh 评分表深度解读——“全量保留“背后的 50% 精确率

PostHog ReviewHog 验证器模型评估:Sonnet 5 xhigh 评分表深度解读——"全量保留"背后的 50% 精确率 【免费下载链接】posthog :hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observabili…

📅 2026/9/18 9:59:56
SpringBoot+Vue社区医疗系统开发实战

SpringBoot+Vue社区医疗系统开发实战

1. 项目概述与核心价值这个基于SpringBootVue的社区医疗服务系统管理平台,是我在指导大学生毕业设计过程中反复打磨的一个实战项目。它完美契合计算机相关专业学生完成毕业设计、课程设计的需求,同时也适合有一定Java基础的开发者作为全栈技术学习案例。…

📅 2026/9/18 9:59:56
MORE NEWS

更多资讯

📰

TypeSpec OpenAPI3 数据模型指南:ExternalDocs 与 TagMetadata 类型详解

TypeSpec OpenAPI3 数据模型指南:ExternalDocs 与 TagMetadata 类型详解 【免费下载链接】typespec 项目地址: https://gitcode.com/GitHub_Trending/ty/typespec 导读 TypeSpec 编译器在将服务定义发射为 OpenAPI 3 文档时,会用到一套预定义的…

📰

前端接口抓取与Mock数据实战:Network面板、跨域代理和分页鉴权

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

产线调试与工控经验谈:从伺服干扰排查到国产化平台应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

FPGA竞赛备赛全攻略:从选题到调试到现场演示的完整时间表

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

VMware嵌套虚拟化开启指南:解决Docker/K8s报错

1. 为什么在 VMware 虚拟机里还要“再开一次虚拟化”?——这不是套娃,是嵌套虚拟化的刚需你刚在 Windows 主机上装好 VMware Workstation Pro,新建了一台 Ubuntu 虚拟机,想在里面跑 Docker Desktop 或者 Kubernetes Minikube&…

📰

发动机试验台架方案:物理-数字映射与动态验证闭环

简介:本资源是一份完整的柴油发动机试验台架技术方案文档,面向汽车工程、动力机械及测试计量领域的工程师、高校教师与研究生,解决发动机出厂测试系统设计与实验室建设中的核心工程问题。方案涵盖试验室规划(供电/气、冷却水、通风…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬