
Cloudflare Cron Triggers 完全指南Workers 定时任务的配置、API 与生产级实践【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills本指南以 Codex Skills 目录skills4/skills 仓库中cloudflare-deploy技能下的 cron-triggers 参考集 为主体系统讲解如何在 Cloudflare Workers 上通过 Cron Triggers 调度定时任务。你将掌握 5 字段 Cron 语法含 Quartz 扩展字符、wrangler.jsonc 配置、scheduled处理器 API、Green Compute 低碳调度、环境差异化配置以及幂等、安全、可观测等生产级实战模式。读完本文即可独立完成从第一个定时 Worker到多 Worker 组合调度 自动化测试的完整落地。Cloudflare Cron Triggers 允许开发者使用 Cron 表达式在 Cloudflare 全球网络上按计划触发 Workers 执行并特意安排在网络低利用率时段运行。它不需要自建调度服务器、不需要常驻进程配置一经部署即可在全球 300 多个节点按 UTC 时间统一触发。在本仓库中它是cloudflare-deploy技能参见 SKILL.md决策树里需要运行代码 → 定时任务cron的官方推荐路径与 Workflows长时多步任务、Queues消息队列、Durable Objects有状态协调等产品可以组合使用。关键特性一览仅 UTC 执行所有调度均基于 UTC 时间无本地时区支持跨地域团队协作时时间语义一致5 字段 Cron 语法原生支持 Quartz 调度器扩展字符L、W、#表达能力远超标准 5 字段 Cron全球传播配置变更后最长约 15 分钟在全球生效至少一次投递At-least-once delivery极端情况下可能出现重复执行业务侧需做幂等处理Workflow 集成可直接触发 Workflows 运行多步骤、长时任务Green ComputeBeta可选碳感知调度在电网碳强度较低的时段执行任务。Cron 语法详解Cron Triggers 采用标准的 5 字段 Cron 语法字段结构与含义如下┌─────────── minute (0-59) │ ┌───────── hour (0-23) │ │ ┌─────── day of month (1-31) │ │ │ ┌───── month (1-12, JAN-DEC) │ │ │ │ ┌─── day of week (1-7, SUN-SAT, 1Sunday) * * * * *支持的扩展字符字符含义示例*任意值每个时间单位都匹配0 * * * *每小时整点,列表枚举多个值0 9,18 * * *每天 9 点与 18 点-范围0 9-17 * * *每天 9 点到 17 点/步进间隔*/5 * * * *每 5 分钟Llast月末/周最后一天0 9 L * *每月最后一天 9 点Wweekday最近的工作日与L组合可用于月末最近工作日#nth第 N 个星期几0 10 * * MON#2每月第二个周一 10 点注意与标准 Unix Cron 不同这里的星期字段1 代表 Sunday1-7SUN-SAT。月份支持数字1-12或三字母缩写JAN-DEC。常用调度表达式*/5 * * * * # 每 5 分钟 0 * * * * # 每小时整点 0 2 * * * # 每天 UTC 2:00非高峰时段 0 9 * * MON-FRI # 工作日 UTC 9:00 0 0 1 * * # 每月 1 日 UTC 0:00 0 9 L * * # 每月最后一天 UTC 9:00 0 10 * * MON#2 # 每月第二个周一 UTC 10:00 */10 9-17 * * MON-FRI # 工作日 9:00-17:00 之间每 10 分钟校验与常见错误Wrangler 会在部署时校验表达式语法但不会捕获逻辑错误。可以在部署前用 crontab.guru 这类交互式校验工具核对表达式的实际匹配时间。三个最典型的错误详见 configuration.md0 0 * * *是每天 UTC 0:00不是你的本地时区零点*/60 * * * *是非法的分钟字段范围是 0-59每小时请写0 * * * *0 2 31 * *只会在有 31 天的月份执行。快速开始部署第一个定时 Worker一个完整的 Cron Trigger 由两部分组成wrangler 配置中的触发器声明 Worker 源码中的scheduled处理器。1. 编写 wrangler.jsonc{ name: my-cron-worker, triggers: { crons: [*/5 * * * *, 0 2 * * *] } }这里声明了两个触发器一个每 5 分钟执行一次一个每天 UTC 2:00 执行一次。两个表达式共享同一个scheduled处理器处理器内通过controller.cron区分当前命中的是哪一个。2. 实现 scheduled 处理器export default { async scheduled( controller: ScheduledController, env: Env, ctx: ExecutionContext, ): Promisevoid { console.log(Cron:, controller.cron); console.log(Time:, new Date(controller.scheduledTime)); ctx.waitUntil(asyncTask(env)); // 非阻塞挂起后台任务 }, };controller提供本次触发的 Cron 表达式与计划执行时间env是 Worker 的绑定环境KV、R2、D1、Secrets、Service Bindings 等都从这里取ctx.waitUntil()把耗时的后台任务挂在事件上不阻塞处理器返回。3. 本地验证npx wrangler dev curl http://localhost:8787/__scheduled?cron*/5****Wrangler 的本地开发服务器会暴露一个__scheduled测试端点通过查询参数模拟任意 Cron 触发空格必须 URL 编码为。详细的参数说明见后文测试策略一节。配置详解wrangler.jsonc 全字段完整的配置示例来自 configuration.md{ $schema: ./node_modules/wrangler/config-schema.json, name: my-cron-worker, main: src/index.ts, compatibility_date: 2025-01-01, // 新项目请使用当前日期 triggers: { crons: [ */5 * * * *, // 每 5 分钟 0 */2 * * *, // 每 2 小时 0 9 * * MON-FRI, // 工作日 UTC 9:00 0 2 1 * * // 每月 1 日 UTC 2:00 ] } }触发器管理规则删除全部触发器显式写入空数组triggers: { crons: [] }保留现有触发器直接省略整个triggers字段部署时不会改动线上触发器。环境差异化调度同一 Worker 可以在不同环境production/staging/dev下使用不同的调度频率避免开发环境高频触发消耗生产配额{ name: my-cron-worker, triggers: { crons: [0 */6 * * *] // 生产每 6 小时 }, env: { staging: { triggers: { crons: [*/15 * * * *] // 预发每 15 分钟 } }, dev: { triggers: { crons: [*/5 * * * *] // 开发每 5 分钟 } } } }部署时通过--env指定目标环境见下文部署命令各环境使用自己的触发器列表互不干扰。Green Compute低碳时段调度BetaGreen Compute 是 Cloudflare 提供的碳感知调度能力Cloudflare 会延迟任务执行直到所在电网区域的碳强度更低从而让定时任务在绿色时段运行。{ name: eco-cron-worker, triggers: { crons: [0 2 * * *] }, placement: { mode: smart // 在低碳时段执行 } }两种模式模式行为smart碳感知调度最长可延迟 24 小时以等待最优执行窗口默认不配置 placement标准调度按 Cron 表达式准时执行无延迟工作机制Cloudflare 将任务执行推迟至电网碳强度更低的时间点从计划时间算起最长延迟 24 小时。适合的场景夜间数据处理与 ETL 流水线、周报/月报生成、数据库备份与维护、分析聚合、ML 模型训练等对时间弹性要求高的批处理任务。不适合的场景有时效要求的操作SLA、面向用户的即时功能、实时监控告警、有严格执行窗口的合规任务。部署命令# 使用配置中的触发器部署 npx wrangler deploy # 部署指定环境 npx wrangler deploy --env production # 查看部署历史 npx wrangler deployments list⚠️ 配置变更最长需要15 分钟才能在全球传播生效验证新调度时请预留等待时间。通过 REST API 管理触发器除 Wrangler CLI 外也可以直接调用 Cloudflare API v4 管理触发器以{account_id}替换你的账户 ID、{script_name}替换脚本名、{api_token}替换带权限的 API Token# 获取当前触发器 curl https://api.cloudflare.com/client/v4/accounts/{account_id}/workers/scripts/{script_name}/schedules \ -H Authorization: Bearer {api_token} # 更新触发器 curl -X PUT https://api.cloudflare.com/client/v4/accounts/{account_id}/workers/scripts/{script_name}/schedules \ -H Authorization: Bearer {api_token} \ -H Content-Type: application/json \ -d {crons: [*/5 * * * *, 0 2 * * *]} # 删除全部触发器 curl -X PUT https://api.cloudflare.com/client/v4/accounts/{account_id}/workers/scripts/{script_name}/schedules \ -H Authorization: Bearer {api_token} \ -H Content-Type: application/json \ -d {crons: []}多 Worker 组合调度对于复杂调度需求频率差异大、任务彼此独立官方推荐拆分为多个 Worker 而非塞进一个// worker-frequent.jsonc { name: data-sync-frequent, triggers: { crons: [*/5 * * * *] } } // worker-daily.jsonc { name: reports-daily, triggers: { crons: [0 2 * * *] }, placement: { mode: smart } } // worker-weekly.jsonc { name: cleanup-weekly, triggers: { crons: [0 3 * * SUN] } }拆分收益每个 Worker 拥有独立的 CPU 时间限制、故障互相隔离、可分别配置不同的 Green Compute 策略也更容易单独维护与调试。典型组合是高频数据同步每 5 分钟 日报生成每日 2 点低碳模式 周清理每周日 3 点。Handler API 详解scheduled 处理器的完整能力API 细节来自 api.md。基础处理器export default { async scheduled(controller: ScheduledController, env: Env, ctx: ExecutionContext): Promisevoid { console.log(Cron executed:, new Date(controller.scheduledTime)); }, };JavaScript 使用相同签名无类型标注Python 版本则写成class Default(WorkerEntrypoint): async def scheduled(self, controller, env, ctx)Python 完整示例见下文实战模式。ScheduledController 接口interface ScheduledController { scheduledTime: number; // Unix 毫秒时间戳计划执行时间 cron: string; // 命中本次执行的表达式如 */5 * * * * type: string; // 恒为 scheduled noRetry(): void; // 阻止失败后的自动重试 }三个处理器参数参数作用controller: ScheduledController访问 Cron 表达式与计划执行时间调用noRetry()env: Env所有绑定KV、R2、D1、Secrets、Service Bindings 等ctx: ExecutionContextctx.waitUntil(promise)延长执行时间承接异步任务日志、清理、外部 API第一次waitUntil的失败会被记录到 Cron Events多触发器路由一个 Handler 处理多个 Cronexport default { async scheduled(controller, env, ctx) { switch (controller.cron) { case */3 * * * *: ctx.waitUntil(updateRecentData(env)); break; case 0 * * * *: ctx.waitUntil(processHourlyAggregation(env)); break; case 0 2 * * *: ctx.waitUntil(performDailyMaintenance(env)); break; default: console.warn(Unhandled: ${controller.cron}); } }, };每个 Cron 表达式对应一个分支未匹配的表达式走default分支并打日志便于发现配置漂移。ctx.waitUntil 的典型用法关键路径critical path上的操作应直接await其余后台任务交给waitUntil并行执行export default { async scheduled(controller, env, ctx) { const data await fetchCriticalData(); // 关键路径必须等待 // 非阻塞后台任务 ctx.waitUntil(Promise.all([ logToAnalytics(data), cleanupOldRecords(env.DB), notifyWebhook(env.WEBHOOK_URL, data), ])); }, };注意waitUntil里的 Promise 若被拒绝且无错误处理会静默失败详见下文陷阱与排障。Workflow 集成触发长时多步任务Cron 适合短时任务长时间运行的多步骤任务应交给 Cloudflare Workflowsimport { WorkflowEntrypoint } from cloudflare:workers; export class DataProcessingWorkflow extends WorkflowEntrypoint { async run(event, step) { const data await step.do(fetch-data, () fetchLargeDataset()); const processed await step.do(process-data, () processDataset(data)); await step.do(store-results, () storeResults(processed)); } } export default { async scheduled(controller, env, ctx) { const instance await env.MY_WORKFLOW.create({ params: { scheduledTime: controller.scheduledTime, cron: controller.cron }, }); console.log(Started workflow: ${instance.id}); }, };Cron 只负责按时拉起Workflow 实例把执行时间scheduledTime与表达式cron作为参数传入Workflow 内部按step.do步骤持久化执行、自动重试。这是官方推荐的定时触发 长任务组合方案参见 workflows 参考集。错误处理与自动重试重试机制失败的 Cron 执行会被自动重试除非调用了noRetry()重试发生在延迟之后通常是数分钟级Cron Events 中只记录第一次waitUntil()的失败。noRetry() 适用场景外部 API 故障避免持续轰炸已故障的服务限流错误立即重试必然再次失败检测到重复执行幂等检查失败非关键任务可接受跳过分析、缓存类校验类错误重试也无法解决。最佳实践示例export default { async scheduled(controller, env, ctx) { try { await criticalOperation(env); } catch (error) { // 记录完整错误上下文 console.error(Cron failed:, { cron: controller.cron, scheduledTime: controller.scheduledTime, error: error.message, stack: error.stack, }); // 决策重试 or 跳过 if (error.message.includes(rate limit)) { controller.noRetry(); // 限流错误跳过重试 } // 其余情况抛出允许自动重试 throw error; } }, };export default { async scheduled(controller, env, ctx) { try { await riskyOperation(env); } catch (error) { // 失败可接受明确禁止重试 controller.noRetry(); console.error(Operation failed, not retrying:, error); } }, };实战模式七种高频业务场景以下完整可运行示例来自 patterns.md。1. API 数据同步含缓存export default { async scheduled(controller, env, ctx) { const response await fetch(https://api.example.com/data, {headers: { Authorization: Bearer ${env.API_KEY} }}); if (!response.ok) throw new Error(API error: ${response.status}); ctx.waitUntil(env.MY_KV.put(cached_data, JSON.stringify(await response.json()), {expirationTtl: 3600})); }, };定时拉取外部 API 数据并写入 KVTTL 设为 3600 秒配合 Worker 的fetch路径即可实现定时刷新缓存。2. 数据库清理export default { async scheduled(controller, env, ctx) { const result await env.DB.prepare(DELETE FROM sessions WHERE expires_at datetime(now)).run(); console.log(Deleted ${result.meta.changes} expired sessions); ctx.waitUntil(env.DB.prepare(VACUUM).run()); }, };用 D1 的prepare().run()批量删除过期会话再异步执行VACUUM回收空间——适合每日凌晨的维护窗口。3. 周报生成export default { async scheduled(controller, env, ctx) { const startOfWeek new Date(); startOfWeek.setDate(startOfWeek.getDate() - 7); const { results } await env.DB.prepare(SELECT date, revenue, orders FROM daily_stats WHERE date ? ORDER BY date).bind(startOfWeek.toISOString()).all(); const report {period: weekly, totalRevenue: results.reduce((sum, d) sum d.revenue, 0), totalOrders: results.reduce((sum, d) sum d.orders, 0), dailyBreakdown: results}; const reportKey reports/weekly-${Date.now()}.json; await env.REPORTS_BUCKET.put(reportKey, JSON.stringify(report)); ctx.waitUntil(env.SEND_EMAIL.fetch(https://example.com/send, {method: POST, body: JSON.stringify({to: teamexample.com, subject: Weekly Report, reportUrl: https://reports.example.com/${reportKey}})})); }, };聚合一周数据、写入 R2 对象存储再通过 Service Binding 调用邮件发送服务通知团队——生成与投递分离。4. 服务健康检查export default { async scheduled(controller, env, ctx) { const services [{name: API, url: https://api.example.com/health}, {name: CDN, url: https://cdn.example.com/health}]; const checks await Promise.all(services.map(async (service) { const start Date.now(); try { const response await fetch(service.url, { signal: AbortSignal.timeout(5000) }); return {name: service.name, status: response.ok ? up : down, responseTime: Date.now() - start}; } catch (error) { return {name: service.name, status: down, responseTime: Date.now() - start, error: error.message}; } })); ctx.waitUntil(env.STATUS_KV.put(health_status, JSON.stringify(checks))); const failures checks.filter(c c.status down); if (failures.length 0) ctx.waitUntil(fetch(env.ALERT_WEBHOOK, {method: POST, body: JSON.stringify({text: ${failures.length} service(s) down: ${failures.map(f f.name).join(, )}})})); }, };并发探测多个服务AbortSignal.timeout(5000)保证单次探测不超过 5 秒结果写入 KV 供状态页读取故障时向 Webhook 推送告警。5. 限流感知的批量处理export default { async scheduled(controller, env, ctx) { const queueData await env.QUEUE_KV.get(pending_items, json); if (!queueData || queueData.length 0) return; const batch queueData.slice(0, 100); const results await Promise.allSettled(batch.map(item fetch(https://api.example.com/process, {method: POST, headers: {Authorization: Bearer ${env.API_KEY}, Content-Type: application/json}, body: JSON.stringify(item)}))); console.log(Processed ${results.filter(r r.status fulfilled).length}/${batch.length} items); ctx.waitUntil(env.QUEUE_KV.put(pending_items, JSON.stringify(queueData.slice(100)))); }, };以 KV 为队列、每轮最多消费 100 条Promise.allSettled保证单条失败不拖垮整批处理完成后原子地推进队列游标写入剩余项。6. 队列集成Cloudflare Queuesexport default { async scheduled(controller, env, ctx) { const batch await env.MY_QUEUE.receive({ batchSize: 100 }); const results await Promise.allSettled(batch.messages.map(async (msg) { await processMessage(msg.body, env); await msg.ack(); })); console.log(Processed ${results.filter(r r.status fulfilled).length}/${batch.messages.length}); }, };定时从 Queues 拉取消息批量处理逐条ack确认处理失败的未 ack 消息会回到队列等待重投与 Cron 的至少一次语义天然互补。详见 queues 参考集。7. 监控与可观测export default { async scheduled(controller, env, ctx) { const startTime Date.now(); const meta { cron: controller.cron, scheduledTime: controller.scheduledTime }; console.log([START], meta); try { const result await performTask(env); console.log([SUCCESS], { ...meta, duration: Date.now() - startTime, count: result.count }); ctx.waitUntil(env.METRICS.put(cron:${controller.scheduledTime}, JSON.stringify({ ...meta, status: success }), { expirationTtl: 2592000 })); } catch (error) { console.error([ERROR], { ...meta, duration: Date.now() - startTime, error: error.message }); ctx.waitUntil(fetch(env.ALERT_WEBHOOK, { method: POST, body: JSON.stringify({ text: Cron failed: ${controller.cron}, error: error.message }) })); throw error; } }, };为每次执行统一打点开始/成功/失败三段日志 时长成功指标写入 KVTTL 30 天失败实时推送告警并重新抛出以触发平台重试。查看日志用npx wrangler tail或在 Dashboard → Workers Pages → Worker → Logs 查看。8. Durable Objects 协调分布式锁当多个触发可能并发执行同一任务时用 Durable Object 实现互斥export default { async scheduled(controller, env, ctx) { const stub env.COORDINATOR.get(env.COORDINATOR.idFromName(cron-lock)); const acquired await stub.tryAcquireLock(controller.scheduledTime); if (!acquired) { controller.noRetry(); return; } try { await performTask(env); } finally { await stub.releaseLock(); } }, };以固定名称cron-lock定位 Durable Object 实例抢锁失败即noRetry()放弃避免与持有者叠加任务结束后在finally中必然释放锁。详见 durable-objects 参考集。Python 处理器示例from workers import WorkerEntrypoint class Default(WorkerEntrypoint): async def scheduled(self, controller, env, ctx): data await env.MY_KV.get(key) ctx.waitUntil(env.DB.execute(DELETE FROM logs WHERE created_at datetime(now, -7 days)))陷阱与排障高频故障场景与解法整理自 gotchas.md。时区问题最高频现象Cron 相对本地时区在错误的时间执行。原因所有 Cron 一律按 UTC 执行不支持本地时区。解法手动把本地时间换算为 UTCutcHour (localHour - utcOffset 24) % 24换算示例太平洋时间PST, UTC-8早上 9 点 →(9 - (-8) 24) % 24 17→0 17 * * *美东时间EST, UTC-5凌晨 2 点 →(2 - (-5) 24) % 24 7→0 7 * * *日本时间JST, UTC9晚上 6 点 →(18 - 9 24) % 24 33 % 24 9→0 9 * * *夏令时DSTCloudflare 不处理 DST需要手动调整建议把任务安排在受 DST 影响较小的时段如本地 2:00-4:00。Cron 未执行可能原因缺少scheduled()导出、语法无效、传播延迟部署后不足 15 分钟、超出套餐限制。排查步骤确认scheduled已从默认导出对象暴露用校验工具核对表达式部署后等待 15 分钟以上检查套餐触发器配额。重复执行原因至少一次投递语义。解法在 KV 中记录执行 ID 做幂等见下文幂等。执行失败原因CPU 超限、未捕获异常、网络超时、绑定错误。解法try-catch 包裹、AbortController设置超时、长任务用ctx.waitUntil()或交给 Workflows。本地测试不生效404 或处理器未触发原因未导出scheduled()、wrangler 未运行、或端点格式错误。按序排查确认scheduled()已导出export default { async scheduled(controller, env, ctx) { console.log(Cron triggered); }, };启动开发服务器npx wrangler dev使用正确的端点格式空格必须编码为# 正确 curl http://localhost:8787/__scheduled?cron*/5**** # 错误会失败 curl http://localhost:8787/__scheduled?cron*/5 * * * *若 wrangler 版本过旧升级npm install -g wranglerlatestwaitUntil() 后台任务未完成现象ctx.waitUntil()中的后台任务静默失败或根本没执行。原因Promise 被拒绝但无错误处理或处理器在 Promise 落定前就返回。解法始终为 waitUntil 中的 Promise 显式处理错误export default { async scheduled(controller, env, ctx) { // 错误示范失败被静默吞掉 ctx.waitUntil(riskyOperation()); // 正确示范显式错误处理 ctx.waitUntil( riskyOperation().catch(err { console.error(Background task failed:, err); return logError(err, env); }) ); }, };幂等应对至少一次投递问题重复投递导致副作用重复重复扣费、重复发邮件。解法用 KV 记录执行 IDcron scheduledTime唯一标识一次计划执行export default { async scheduled(controller, env, ctx) { const executionId ${controller.cron}-${controller.scheduledTime}; const existing await env.EXECUTIONS.get(executionId); if (existing) { console.log(Already executed, skipping); controller.noRetry(); return; } await env.EXECUTIONS.put(executionId, 1, { expirationTtl: 86400 }); // 24h TTL await performIdempotentOperation(env); }, };先查后写KV 写入前先读取命中则跳过并调用noRetry()执行记录设置 24 小时 TTL 防止 KV 无限膨胀。安全生产环境暴露 __scheduled 端点问题__scheduled测试端点在生产环境同样可用任何人可触发你的 Cron 逻辑。解法在fetch处理器中拦截export default { async fetch(request, env, ctx) { const url new URL(request.url); // 生产环境屏蔽 __scheduled if (url.pathname /__scheduled env.ENVIRONMENT production) { return new Response(Not Found, { status: 404 }); } return handleRequest(request, env, ctx); }, async scheduled(controller, env, ctx) { // 你的 cron 逻辑 }, };补充措施密钥一律走env.API_KEY之类的绑定严禁硬编码也可增加中间件校验请求来源例如要求携带cf-ray头以确认请求来自 Cloudflare 内部链路生产环境缺失即返回 404。注意基于请求头校验只是参考方案最稳妥的做法仍是直接屏蔽或加认证。限额与配额限额项免费版付费版说明每 Worker 触发器数3不限单个 Worker 允许的 Cron 数量上限CPU 时间10ms50ms超限需要ctx.waitUntil()或 Workflows执行保证至少一次至少一次可能重复务必做幂等传播延迟最长 15 分钟最长 15 分钟变更在全球生效所需时间最小间隔1 分钟1 分钟无法调度比 1 分钟更频繁的任务Cron 精度±1 分钟±1 分钟执行时间可能有轻微漂移测试策略从本地到生产本地开发__scheduled 端点# 启动开发服务器 npx wrangler dev # 触发任意 Cron curl http://localhost:8787/__scheduled?cron*/5**** # 指定 Cron 与自定义时间毫秒级 Unix 时间戳 curl http://localhost:8787/__scheduled?cron02***scheduledTime1704067200000查询参数cron— 必填。URL 编码后的 Cron 表达式空格用表示scheduledTime— 可选。Unix 毫秒时间戳默认取当前时间。再次提醒该端点在生产环境同样存在且可被任何人触发必须屏蔽或加认证见上文安全一节。单元测试Vitest cloudflare:test// test/scheduled.test.ts import { describe, it, expect } from vitest; import { env } from cloudflare:test; import worker from ../src/index; describe(Scheduled Handler, () { it(processes scheduled event, async () { const controller { scheduledTime: Date.now(), cron: */5 * * * *, type: scheduled as const, noRetry: () {} }; const ctx { waitUntil: (p: Promiseany) p, passThroughOnException: () {} }; await worker.scheduled(controller, env, ctx); expect(await env.MY_KV.get(last_run)).toBeDefined(); }); it(handles multiple crons, async () { const ctx { waitUntil: () {}, passThroughOnException: () {} }; await worker.scheduled({ scheduledTime: Date.now(), cron: */5 * * * *, type: scheduled, noRetry: () {} }, env, ctx); expect(await env.MY_KV.get(last_type)).toBe(frequent); }); });带 vi 断言的幂等测试// test/scheduled.test.ts import { describe, it, expect, vi } from vitest; import { env } from cloudflare:test; import worker from ../src/index; describe(Scheduled Handler, () { it(executes cron, async () { const controller { scheduledTime: Date.now(), cron: */5 * * * *, type: scheduled as const, noRetry: vi.fn() }; const ctx { waitUntil: vi.fn(), passThroughOnException: vi.fn() }; await worker.scheduled(controller, env, ctx); expect(await env.MY_KV.get(last_run)).toBeDefined(); }); it(calls noRetry on duplicate, async () { const controller { scheduledTime: 1704067200000, cron: 0 2 * * *, type: scheduled as const, noRetry: vi.fn() }; await env.EXECUTIONS.put(0 2 * * *-1704067200000, 1); await worker.scheduled(controller, env, { waitUntil: vi.fn(), passThroughOnException: vi.fn() }); expect(controller.noRetry).toHaveBeenCalled(); }); });第二个用例先在 KV 预置执行记录再断言幂等逻辑正确调用noRetry()。测试最佳实践单元测试mockScheduledController、ExecutionContext与绑定每个 Cron 表达式单独测试断言noRetry()在预期时机被调用使用 Vitest cloudflare/vitest-pool-workers获得接近真实的绑定环境集成测试在开发环境通过__scheduled端点验证用重复的scheduledTime验证幂等逻辑覆盖错误处理与重试行为生产上线先用长间隔如*/30 * * * *观察持续监控 Cron Events 24 小时配置告警后再逐步缩短间隔。阅读顺序与配套参考本指南对应的完整参考集位于 skills/.curated/cloudflare-deploy/references/cron-triggers/按需取用新手上手先读本文总览 快速开始再依次阅读 configuration.md首个触发器配置、api.mdHandler API、patterns.md常见用例遇到问题直接跳到 gotchas.md 对照排障功能对比长时多步定时任务可参考 workflows 参考集Worker 运行时基础能力见 workers 参考集。核心要点回顾Cron Triggers 把定时触发从自建基础设施中解放出来——5 字段 Quartz 扩展语法覆盖绝大多数周期场景15 分钟全球传播与 UTC-only 语义需要纳入发布与排障预期至少一次投递决定了幂等是生产底线10ms/50ms 的 CPU 上限则提示短触发 后台挂起的正确姿势。遇到真正长时、多步骤的任务时用 Cron 拉起 Workflows把调度与执行解耦即可在 Cloudflare 平台上构建一套完整、可观测、可测试的定时任务体系。【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考