Durable Objects 的 alarm 怎么用?
我在本地用 setAlarm(now + 500ms) 设了一个 alarm,大约半秒后 alarm() 触发;再让它前两次都抛错,第二次、第三次调用的 retryCount 分别是 1 和 2。
所以答案是:用 setAlarm(时间戳毫秒) 设置,到点运行时调用对象的 alarm() 方法。它是每个对象一个的、可持久的定时器,适合会话过期、延迟清理、批量刷盘这类按实体的任务。
但 alarm 有几条语义很容易踩:只有一个、不自动重复、至少执行一次。下面按你会遇到的顺序讲。对象本身的模型见 Durable Objects:单线程模型、一个 ID 一个实例与存储。
最小的 alarm 怎么写?
export class Session extends DurableObject<Env> {
async touch() {
await this.ctx.storage.setAlarm(Date.now() + 30 * 60_000);
}
async alarm(info?: AlarmInvocationInfo) {
this.ctx.storage.sql.exec("DELETE FROM data");
// 周期任务需要在这里再次 setAlarm
}
}touch 每次调用都会把 alarm 推到 30 分钟后,因为同一时刻每个对象只有一个 alarm,再次 setAlarm 会覆盖。
alarm 失败了会怎样?
alarm() 抛未捕获异常时自动重试,从 2 秒起指数退避,最多 6 次,且重试只针对最近一次 setAlarm。想无限重试,就自己捕获异常并重新 setAlarm。
我在本地让 alarm() 前两次都抛错:alarmInfo 里第一次是 retryCount: 0 与 isRetry: false,第二次、第三次的 retryCount 是 1、2,isRetry 为 true,重试间隔大约 2 秒、再约 4 到 5 秒,符合从 2 秒起的指数退避。alarm() 运行期间 getAlarm() 返回 null。
为什么 alarm() 必须幂等?
因为 alarm 保证至少执行一次,不是恰好一次,重试时同一个任务可能被再跑一遍。
怎么做周期任务和多事件?
alarm 不自动重复,周期任务要在处理完之后设置下一次。
多事件的做法是:把待办放进表里,alarm() 处理所有到期项,然后只为最近的下一项设置 alarm。
还有一个坑:对象从休眠中醒来时,构造函数先于 alarm() 运行。构造里如果无条件 setAlarm,会覆盖已有的,要先用 getAlarm() 判断。
alarm 能替代 cron 吗?
不能。alarm 是按实体的定时器,不是全局 cron。全站定时任务用 Workers 的 Cron Triggers;跨步骤、可恢复的长流程见 Workflows;需要可靠地「至少一次」投递给别的系统,见 Queues。
计费上,每次 setAlarm 在 SQLite 后端计一次写入,每次 alarm 调用计一次请求。
500 毫秒触发、retryCount与isRetry的变化、重试间隔和getAlarm()返回null,我在本地 workerd 上跑过,线上的调度精度我没测过。单个 alarm 的覆盖语义、至少一次、最多 6 次重试、构造函数先于alarm()运行,以及计费方式,都来自官方文档,我没有验证过。数值会变化,以 2026-10 的官方文档为准。