快速开始
在当前进程中按计划运行回调:Bun.cron.parse()
解析 cron 表达式,并返回系统本地时区中下一个匹配的 Date。
参数
返回值
Date | null — 下一个匹配的时间;如果在 8 年内不存在匹配项,则返回 null(例如 2 月 30 日)。
链式调用
重复调用parse() 以获取即将到来的时间序列:
Cron 表达式语法
标准 5 字段格式:minute hour day-of-month month day-of-week
特殊字符
命名值
月份和星期字段接受不区分大小写的名称:0 和 7 都表示星期日。
预定义别名
时区
计划任务按照系统的本地时区进行解释——其方式与 crontab、launchd 和 Windows 任务计划程序读取计划的方式相同。操作系统级形式和进程内回调形式会在相同的墙上时钟时间触发。 如需覆盖默认时区,请将 IANA 时区名称作为{ tz } 传递给 Bun.cron.parse() 或进程内的 Bun.cron(schedule, handler, options):
- 春季调快 — 如果计划任务落在缺失的小时内,则会在当天触发,并因时间间隔而顺延(例如,
30 2 * * *会在春季调快当天的 3:30 运行)。对于缺失小时内的多分钟模式(*/15 2 * * *),只有第一个匹配项会触发。 - 秋季调慢 — 在重复小时内的固定时间计划(
30 1 * * *)只会触发一次,即在第一次出现时触发。分钟或小时字段为*的计划(0 * * * *、* * * * *)会经过两次出现的时间——每个实际时间分钟触发一次,与 Linux 上的 crontab 行为一致。
月份中的日期与星期交互
当同时指定了 day-of-month 和 day-of-week(两者都不是*)时,只要任一条件为真,表达式就会匹配。这遵循 POSIX cron 标准。
*)时,仅使用该字段进行匹配。
Bun.cron(schedule, handler) — 进程内
在当前进程内以 cron 计划运行回调。
参数
同步返回一个
CronJob。如果表达式无效、时区名称未知,或者表达式没有未来的发生时间(例如 "0 0 30 2 *",即 2 月 30 日),则抛出 TypeError。
不重叠保证
只有在 handler(包括任何返回的 Promise)结束之后,才会计算下一次触发时间。如果你的 handler 需要 90 秒,而计划是* * * * *,那么第二次触发将是 handler 完成后的第一个整分钟边界,而不是第一次触发后 60 秒。调用之间不会堆叠。
错误处理
错误行为与setTimeout 保持一致:
- 同步
throw会触发process.on("uncaughtException")。 - 被拒绝的返回
Promise会触发process.on("unhandledRejection")。
1 退出。设置了监听器时,任务会继续运行——不会在第一次失败后停止。
bun --hot
在 bun --hot 下,所有进程内 cron 任务会在模块图重新求值之前立刻停止。之后你源代码中的每次 Bun.cron() 调用都会重新注册。修改计划、修改 handler 或者直接删除那一行,都将在保存时生效,而不会泄漏定时器。
CronJob 句柄
CronJob 是 Disposable —— using job = Bun.cron(...) 会在作用域退出时自动停止。stop()、ref() 和 unref() 都会返回该 job 以便链式调用。
假定时器
进程内 cron 支持jest.useFakeTimers()。setSystemTime()、advanceTimersByTime() 和 runAllTimers() 控制其触发时间,因此你可以无需等待真实时钟即可测试计划回调。
Bun.cron(path, schedule, title) — 操作系统级别
注册一个操作系统级别的 cron 任务,按计划运行 JavaScript/TypeScript 模块。
参数
使用相同的
title 重新注册会就地覆盖现有任务——旧的计划会被替换,而不是重复添加。
scheduled() 处理程序
注册的脚本必须导出一个带有 scheduled() 方法的默认对象,遵循 Cloudflare Workers Cron Triggers API:
worker.ts
async。Bun 会等待返回的 promise 完成后再退出。
各平台的工作原理
Linux
Bun 使用 crontab 注册任务。每个任务作为一行存储在您用户的 crontab 中,上方带有# bun-cron: <title> 标记注释。
crontab 条目如下所示:
scheduled() 处理程序。
查看已注册的任务:
scheduled() 处理程序内添加日志记录。
无需代码手动卸载:
macOS
Bun 使用 launchd 注册任务。每个任务作为 plist 文件安装在:StartCalendarInterval 定义调度计划。支持包含范围、列表或步长的复杂模式 — Bun 会将它们扩展为笛卡尔积形式的多个 StartCalendarInterval 字典。
查看已注册的任务:
weekly-report 的任务:
Windows
Bun 使用基于 XML 任务定义的 Windows Task Scheduler,使用CalendarTrigger 元素和 Repetition 模式。
大多数 cron 表达式都得到完全支持,包括 @daily、@weekly、@monthly、@yearly、范围 (1-5)、列表 (1,15)、命名日/月和日期模式。
用户上下文
Bun 使用S4U(用户服务)登录类型注册任务,即使注册用户未登录,任务也会以该用户身份运行 — 与 Linux crontab 的行为一致。不会存储密码。
TCP/IP 网络(fetch()、HTTP、WebSocket、数据库连接)正常工作。唯一的限制是 S4U 任务无法访问 Windows 身份验证的网络资源(SMB 文件共享、映射驱动器、Kerberos/NTLM 服务)。
在无头服务器和 CI 环境中,如果无法解析当前用户的安全标识符(SID) — 例如由 NSSM 或类似工具创建的服务帐户 — Bun.cron() 将失败,并显示解释该问题的错误信息。要解决此问题,请使用普通用户帐户运行 Bun,或使用 schtasks /create /xml <file> /tn <name> /ru SYSTEM /f 手动创建计划任务。
触发器限制
在所有平台上都有效的表达式:
在 Windows 上失败的表达式(但在 Linux 和 macOS 上有效):
关键因素是表达式是否可以使用
Repetition 间隔(单一触发器),或者必须展开为独立的 CalendarTrigger 元素。能整除 60的分钟步长(*/1、*/2、*/3、*/4、*/5、*/6、*/10、*/12、*/15、*/20、*/30)使用 Repetition,无论其他字段如何都能工作。不能整除 60 的步长(*/7、*/8、*/9、*/11、*/13 等)必须展开,而在 24 小时全天运行的情况下,数量很快会超过 48。
要解决此问题,请简化表达式或限制小时范围:
Windows 容器
查看已注册的任务:bun-cron-<title> 的任务,右键单击并删除它。
Bun.cron.remove()
通过其标题移除先前注册的定时任务。适用于所有平台。
Bun.cron() 的操作:
移除一个不存在的任务会无错误地完成。