别让 Durable Objects 死循环让你破产:需要知道的几件事
karamage 用“按时计费的酒店”解释 Durable Objects 计费,复盘自己的 alarm 死循环如何把个人服务的按量计费预估从几日元推到近 8,000 日元(作者数字),并列出防止失控的四条编码规则和两条及早发现的运维习惯。
- 适用产品
- Durable ObjectsAgents SDK
- 来源
- 作者经验Zenn
- 作者
- karamage
要点
- 他把 Durable Objects 比作按时计费的酒店:对象入住期间即使什么也不做也在计时,每次请求另算一次费用。能不能休眠决定了大部分费用:满足条件的空闲对象约 10 秒后休眠,不能休眠的对象 70 到 140 秒后被逐出,但未完成的 I/O、setTimeout 或 setInterval 各自都会从开始起把对象留在内存里最多 15 分钟。
- 他的事故:通知队列的 alarm() 捕获失败后立刻调用 setAlarm(Date.now())。某个周五通知目标开始返回 400 错误,队列一直清不掉,alarm 立即重新预约,在每个用户各自的对象上整个周末循环。每次 alarm 执行按一次请求计费,每次 setAlarm() 计为一次存储写入,时长计费也一直没停。
- 他还转述了 Hacker News 上的 onStart() 陷阱:onStart() 每次唤醒都会执行,在那里不检查就调用 setAlarm() 会让对象永远睡不着;发帖人有 60 多个预览部署、各有自己的对象,高峰时每天约 9,300 亿次行读取。解决办法:setAlarm() 前先查 getAlarm();用 Agents SDK 的 schedule() 指定延迟或日期时传 { idempotent: true };从预览环境移除 Durable Object 绑定。
- 他的四条编码规则:每个 alarm 都要有终止条件和最小间隔,失败时等待时间指数递增、达到设定次数就放弃;在对象之间传递调用深度,超过上限就中断,因为 A 调 B、B 又调 A 会悄悄形成循环;用 alarm 代替 setInterval,用 ctx.acceptWebSocket()(Hibernation API)代替 accept();先装好紧急停止开关,在 alarm() 开头检查环境变量,标记打开就 deleteAlarm() 并返回,重新部署即可让所有对象停下。
- 运维上他设置预算告警(平时只花几日元的个人项目,他建议设 $5 或 $10),并指出 Durable Objects 没有自动停止用量的硬上限,那位 Hacker News 发帖人的 Workers 用量通知也只看 CPU 时间。他在每次部署后的第二天和周末前查看 Durable Objects 仪表盘的请求数、时长、行读写图表;出现循环时,请求数和写入数会同步飙升,时长居高不下。
- 官方文档(2026-10-16 复核):生命周期页确认 10 秒后休眠、70 到 140 秒后逐出、每个未完成操作最多 15 分钟;Durable Objects 定价把每次 setAlarm() 计为写入一行;Agents SDK schedule() 的去重默认对 cron 为 true,对延迟和指定日期的任务为 false;预算告警仅作提醒,不会暂停或封顶用量。
原始来源
最后更新
别让 Durable Objects 死循环让你破产:需要知道的几件事
打开原始来源karamage 用“按时计费的酒店”解释 Durable Objects 计费,复盘自己的 alarm 死循环如何把个人服务的按量计费预估从几日元推到近 8,000 日元(作者数字),并列出防止失控的四条编码规则和两条及早发现的运维习惯。
其他推荐阅读
作者经验Workers +5
别让小项目跑出大账单:Cloudflare 的四层费用防护
David Z(@davezfr)在 X 长文中面向 Vibe Coder,整理预算提醒、付费路径停止条件、自动暂停,以及由 personal agent 核实并暂停的四层防护。
Workers
RetainDB:81 个用户,队列循环报告约 $36k 账单。
Reddit 用户 alameenswe 在 Workers、KV、Durable Objects 与 Queues 上构建 RetainDB,报告 81 个用户一个月产生约 $36k 的 Cloudflare 账单,正文写作 $35,000。他将其归因于队列消费者反复重新排队异步写入、每次记忆写入 12 次未批处理的 Durable Object 写入,以及鉴权回退中的 kv.list() 扫描。