兰 亭 墨 苑
期货 · 量化 · AI · 终身学习
首页
归档
编辑文章
标题 *
URL 别名 *
内容 *
(支持 Markdown 格式)
这篇文档介绍的是一个对于 Durable Objects 来说至关重要的功能:**WebSocket 休眠 API (WebSocket Hibernation API)**。这个 API 彻底改变了在 Durable Objects 中使用 WebSocket 的成本和效率。 我们先来理解它解决了什么根本问题,然后再看它是如何工作的。 --- ### 1. 核心问题:昂贵的“清醒”状态 想象一下你之前的那个“专属管家”(Durable Object)。 * **传统 WebSocket 模式**:如果一个客户通过 WebSocket(一条持续打开的电话线)连接到这个管家,那么只要这条电话线不断开,管家就必须一直“醒着”待命。他不能去休息(无法关闭实例)。 * **问题所在**:Durable Object 的计费是按“活跃持续时间”来的。如果一个 WebSocket 连接保持 24 小时,哪怕一句话都不说,你的管家也得“清醒”24 小时,这会导致极高的**持续时间费用 (Duration cost)**。对于一个需要支持成百上千个并发连接的聊天室来说,这种成本是无法接受的。 **WebSocket 休眠 API 的目标**:打破“WebSocket 连接存在”与“Durable Object 必须活跃”之间的强制绑定,允许对象在 WebSocket 连接保持的情况下进入“休眠”状态,从而大幅节约成本。 --- ### 2. 解决方案:将 WebSocket “托管”给网络 WebSocket 休眠 API 的工作原理,就像是管家把电话转接到了一个智能总机(Cloudflare 全球网络)上。 1. **接受并“托管” (Accept & Hibernate)**:当一个客户端请求建立 WebSocket 连接时,管家(Durable Object)接起电话,但不是一直拿着它,而是告诉智能总机:“这个客户你帮我看着,有事再叫我。” 然后管家就可以回去睡觉了(实例被关闭,停止计费)。 2. **按需唤醒 (Wake on Demand)**: * **当客户说话时**:如果客户通过 WebSocket 发送了一条消息,智能总机(网络)会立刻叫醒对应的管家,并把消息递给他处理。 * **当管家需要主动说话时**:如果管家因为其他原因(比如另一个用户发了广播消息)需要给这个客户发送消息,他可以告诉总机:“帮我找到A客户的电话线,我要跟他说话。” 3. **处理结束,继续休眠**:管家处理完单个消息后,就可以再次回去睡觉,把连接继续交给总机看管。 这样一来,Durable Object **只在有实际消息需要处理的瞬间才被唤醒并计费**,而不是在整个连接期间都保持活跃。 --- ### 3. API 的具体用法和关键组件 根据您提供的文档,实现这一点的关键 API 如下: #### `acceptWebSocket()` - 接受并标记连接 这是启动休眠的第一步。在你的 `fetch` 处理器中,当你接受 WebSocket 连接时,可以给它附加**标签 (tags)**。 ```javascript // 在 fetch() 方法中 export default { async fetch(request, env, ctx) { // ... const pair = new WebSocketPair(); const [client, server] = Object.values(pair); // 关键步骤:接受连接,并附加标签 this.ctx.acceptWebSocket(server, ["chat", "room:general"]); // "server" 是 DO 这一侧的 socket // 返回客户端的 socket,并立即结束 fetch 处理,允许对象休眠 return new Response(null, { status: 101, webSocket: client }); } } ``` * `acceptWebSocket(socket, tags)`:这个方法告诉运行时:“请接管这个 `socket`。如果它收到消息或关闭,请用下面定义的事件处理器来唤醒我。” * `tags`: 标签是一个字符串数组,非常重要。它就像给这个连接打上了“属于 general 聊天室”的标签,方便以后按标签查找。 #### `getWebSockets()` - 获取休眠中的连接 这个方法允许你从“智能总机”那里把托管的 WebSocket 连接找回来,以便主动给它们发消息(例如广播)。 ```javascript // 示例:广播消息给一个房间里的所有人 async broadcast(message) { // 按标签查找所有属于 "room:general" 的休眠中的连接 const sockets = this.ctx.getWebSockets({ tag: "room:general" }); // 遍历并发送消息 for (const ws of sockets) { ws.send(message); } } ``` * `getWebSockets({ tag: "..." })`:可以按单个标签或多个标签来过滤,获取所有匹配的 WebSocket 实例。 #### 新的事件处理器 - 处理唤醒事件 当一个被托管的 WebSocket 收到消息或关闭时,Durable Object 会被唤醒,并调用下面这些新的顶级事件处理器(这些方法要和 `fetch` 并列定义在类中)。 * **`webSocketMessage(ws, message)`**: 当休眠的 `ws` 收到 `message` 时被调用。 ```javascript async webSocketMessage(ws, message) { // 可以在这里处理收到的消息,例如存入数据库,或者广播给其他人 // ws.send("You said: " + message); // await this.broadcast(message); } ``` * **`webSocketClose(ws, code, reason, wasClean)`**: 当休眠的 `ws` 连接关闭时被调用。你可以在这里进行清理工作,比如更新在线用户列表。 * **`webSocketError(ws, error)`**: 当休眠的 `ws` 发生错误时被调用。 --- ### 总结与优势 | API / Handler | 用途 | 比喻 | | :--- | :--- | :--- | | **`acceptWebSocket(ws, tags)`** | 接受连接并将其“托管”给网络,同时打上标签。 | 管家把电话转接给总机,并告诉总机这是“聊天室”的电话。 | | **`getWebSockets({tag: ...})`** | 根据标签找回一个或多个被托管的连接。 | 管家让总机帮他找出所有“聊天室”的电话线,准备广播。 | | **`webSocketMessage(ws, msg)`** | 当被托管的连接收到消息时,唤醒对象并执行此函数。 | 总机发现有客户说话,立刻叫醒管家,并把话传给他。 | | **`webSocketClose()`** | 当连接关闭时,唤醒对象执行此函数。 | 总机发现客户挂了电话,通知管家一声。 | **核心优势**: 1. **极大降低成本**:这是最主要的优势。费用从“按连接时长”变为“按实际消息处理时间”,成本可能降低几个数量级。 2. **提升可扩展性**:一个 Durable Object 实例可以轻松管理成千上万个并发 WebSocket 连接,因为它不需要在内存中维护所有连接,极大地减少了内存占用。 3. **简化状态管理**:开发者不再需要自己手动在 `storage` 中存储和追踪所有 WebSocket 的状态,平台为你搞定了一切。
配图 (可多选)
选择新图片文件或拖拽到此处
标签
更新文章
删除文章