agents/schedules 中的 Scheduler 可在未来运行已注册的回调:延迟一段时间后、指定日期、按 cron 表达式或按固定间隔运行。计划会作为作业存储在 Lifecycle 作业队列中,因此对象被逐出后仍会保留,并与其他能力共享对象的闹钟。
在构造函数中按名称注册回调,然后将调度器安装到 Lifecycle 上:
import { DurableObject } from "cloudflare:workers";
import { getCurrentAgent, Lifecycle } from "agents/lifecycle";
import { Scheduler } from "agents/schedules";
export class ReminderAgent extends DurableObject {
scheduler = new Scheduler({
callbacks: {
sendReminder: (payload, schedule) => {
const { agent } = getCurrentAgent();
console.log(
`${agent?.lifecycle.name}: reminder ${schedule.id}: ${payload.message}`,
);
},
},
});
lifecycle = Lifecycle.install(this).use(this.scheduler);
async onStart() {
// Cron schedules are idempotent, so this adds one row, not one per wake.
await this.scheduler.set("0 8 * * 1-5", "sendReminder", {
message: "Good morning",
});
}
async onRequest() {
const schedule = await this.scheduler.set(300, "sendReminder", {
message: "Five minutes have passed",
});
return Response.json(schedule, { status: 201 });
}
}import { DurableObject } from "cloudflare:workers";
import { getCurrentAgent, Lifecycle } from "agents/lifecycle";
import { Scheduler, type Schedule } from "agents/schedules";
type Reminder = { message: string };
export class ReminderAgent extends DurableObject<Env> {
readonly scheduler = new Scheduler({
callbacks: {
sendReminder: (payload: Reminder, schedule: Schedule<Reminder>) => {
const { agent } = getCurrentAgent<ReminderAgent>();
console.log(
`${agent?.lifecycle.name}: reminder ${schedule.id}: ${payload.message}`,
);
},
},
});
readonly lifecycle = Lifecycle.install(this).use(this.scheduler);
async onStart(): Promise<void> {
// Cron schedules are idempotent, so this adds one row, not one per wake.
await this.scheduler.set("0 8 * * 1-5", "sendReminder", {
message: "Good morning",
});
}
async onRequest(): Promise<Response> {
const schedule = await this.scheduler.set(300, "sendReminder", {
message: "Five minutes have passed",
});
return Response.json(schedule, { status: 201 });
}
}每个计划只存储回调名称,不存储函数。对象每次启动时都会重建回调映射,因此逐出前创建的计划会在对象唤醒后找到对应回调。请在字段初始化器中无条件注册每个回调。
set() 和 every() 会根据映射检查回调名称和有效负载类型。回调会收到有效负载和触发该回调的 Schedule。它会在对象的调用上下文中运行,因此 getCurrentAgent() 会返回该对象。
| 选项 | 说明 |
|---|---|
callbacks |
命名回调 (payload, schedule) => unknown |
retry |
回调的默认重试策略:{ maxAttempts, baseDelayMs, maxDelayMs }。默认值依次为 3、100 和 3000。 |
hungScheduleTimeoutSeconds |
运行中的间隔计划在被视为已放弃前等待的秒数。默认值为 30。 |
onError |
(error) => void。在回调最后一次重试失败后接收通知。 |
set(when, callback, payload?, options?) 将时间作为第一个参数。when 的类型决定运行模式:
when |
模式 | 示例 |
|---|---|---|
number |
delayed |
set(60, "sendReminder", payload) 会在 60 秒后运行。 |
Date |
scheduled |
set(new Date("2026-12-25T09:00:00Z"), ...) |
string |
cron |
set("0 8 * * 1-5", ...) 会在工作日 UTC 时间 08:00 运行。 |
every(intervalSeconds, callback, payload?, options?) 会创建一个 interval 计划:
await this.scheduler.every(30, "sendReminder", { message: "Every 30 seconds" });第一次间隔运行会在 intervalSeconds 秒后发生,而不是立即运行。如果上一次运行在下一次到期时仍未完成,调度器会跳过那次运行。
这两个方法都会返回已存储的 Schedule。它包含 id、callback 名称、payload、type 以及以 Unix 秒为单位的下一次运行 time。根据类型,它还会包含 delayInSeconds、cron 或 intervalSeconds。
将选项作为第四个参数传入:
| 选项 | 说明 |
|---|---|
retry |
覆盖此计划的调度器重试策略 |
idempotent |
若存在具有相同回调、时间和有效负载的计划,则返回该计划,而不是添加新记录。 |
idempotent 对 cron 和间隔计划默认为 true。你可以在 onStart() 中创建重复计划,而不会在每次唤醒时都添加新记录。对于延迟和定时计划,默认值为 false;每次调用都会添加一条记录,除非传入 { idempotent: true }。
| 方法 | 说明 |
|---|---|
get(id) |
返回一个计划,若不存在则返回 undefined。 |
list(criteria?) |
返回计划列表,可按 id、type 或 timeRange: { start?, end? } 筛选。 |
cancel(id) |
移除一个计划。若移除了计划则返回 true。 |
import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { Scheduler } from "agents/schedules";
export class ReminderAgent extends DurableObject {
scheduler = new Scheduler({
callbacks: {
sendReminder: (payload) => console.log(payload.message),
},
retry: { maxAttempts: 5, baseDelayMs: 500, maxDelayMs: 10_000 },
onError: (error) => console.error("Reminder failed", error),
});
lifecycle = Lifecycle.install(this).use(this.scheduler);
// An RPC method, so it starts the Lifecycle itself.
async resetReminders() {
await this.lifecycle.start();
const crons = await this.scheduler.list({ type: "cron" });
for (const schedule of crons) {
await this.scheduler.cancel(schedule.id);
}
await this.scheduler.set(
60,
"sendReminder",
{ message: "Reminders reset" },
{ idempotent: true, retry: { maxAttempts: 1 } },
);
return crons.length;
}
}import { DurableObject } from "cloudflare:workers";
import { Lifecycle } from "agents/lifecycle";
import { Scheduler } from "agents/schedules";
type Reminder = { message: string };
export class ReminderAgent extends DurableObject<Env> {
readonly scheduler = new Scheduler({
callbacks: {
sendReminder: (payload: Reminder) => console.log(payload.message),
},
retry: { maxAttempts: 5, baseDelayMs: 500, maxDelayMs: 10_000 },
onError: (error) => console.error("Reminder failed", error),
});
readonly lifecycle = Lifecycle.install(this).use(this.scheduler);
// An RPC method, so it starts the Lifecycle itself.
async resetReminders(): Promise<number> {
await this.lifecycle.start();
const crons = await this.scheduler.list({ type: "cron" });
for (const schedule of crons) {
await this.scheduler.cancel(schedule.id);
}
await this.scheduler.set(
60,
"sendReminder",
{ message: "Reminders reset" },
{ idempotent: true, retry: { maxAttempts: 1 } },
);
return crons.length;
}
}一次性计划运行后会被删除。cron 或间隔计划则会更新为下一次运行时间。
抛出异常的回调会按指数退避策略重试,最多达到 maxAttempts 次。最后一次尝试后会运行 onError。随后会移除一次性计划;重复计划则会继续安排下一次运行。
如果对象在回调运行期间被逐出,Lifecycle 闹钟会再次唤醒对象,并重新运行该回调。请确保外部操作具有幂等性。
- Cron 计划精确到分钟。间隔计划精确到秒。
- 回调会与对象上的其他作业逐个运行。请保持回调简短。
- 有效负载必须可序列化为 JSON。
agents/schedules/parser 导出一个提示和 Zod 架构,可将“每周一上午 9 点提醒我”之类的请求转换为结构化计划。请将它们与支持结构化输出的模型调用搭配使用:
import { getSchedulePrompt, scheduleSchema } from "agents/schedules/parser";
import { generateObject } from "ai";
export async function parseRequest(input) {
const { object } = await generateObject({
model,
schema: scheduleSchema,
system: getSchedulePrompt({ date: new Date() }),
prompt: input,
});
return object; // { description, when: { type: "delayed", delayInSeconds } | ... }
}import { getSchedulePrompt, scheduleSchema } from "agents/schedules/parser";
import { generateObject, type LanguageModel } from "ai";
declare const model: LanguageModel;
export async function parseRequest(input: string) {
const { object } = await generateObject({
model,
schema: scheduleSchema,
system: getSchedulePrompt({ date: new Date() }),
prompt: input,
});
return object; // { description, when: { type: "delayed", delayInSeconds } | ... }
}when.type 可以是 scheduled(带有 date)、delayed(带有 delayInSeconds)、cron(带有 cron 表达式)或 no-schedule。旧的 agents/schedule 导入路径仍可使用,但已弃用。
调度器会向 agents:schedule 诊断通道发布 schedule:create、schedule:execute、schedule:retry、schedule:error 和 schedule:cancel 事件。
Agent 类会安装 Scheduler。它的 this.schedule()、this.scheduleEvery()、this.getSchedule()、this.listSchedules() 和 this.cancelSchedule() 方法都会调用该能力,回调名称则对应 Agent 上的方法。更多信息,请参阅安排任务。