关于 boxlang-scheduled-tasks
面向 BoxLang 应用的定时任务技能,涵盖进程内代码调度和持久化 HTTP 触发任务,并说明注册、生命周期控制、频率设置及集群执行。
主要功能
- 01在 Application.bx 注册调度器类
- 02用流式 DSL 调度回调任务
- 03通过 BIF 管理调度器生命周期
- 04持久化并控制 HTTP 触发任务
- 05配置 cron 与日历频率
- 06将任务限定在集群单节点运行
适用场景
- 01安排周期性维护回调
- 02触发 webhook 或运维端点
- 03检查或控制调度器实例
- 04避免集群节点重复执行任务
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ ortus-boxlang/ skills --skill boxlang-scheduled-tasks安装后在 Claude Code 中输入/boxlang-scheduled-tasks确认已加载。
详细介绍
BoxLang 定时任务
BoxLang 是一个 AI 原生的软件生产力平台,用于构建、现代化改造和运行应用,让开发者与 AI Agent 携手协作。
概览
BoxLang 提供两种调度模式:
- 调度器 DSL(进程内代码执行):使用由
BaseScheduler和ScheduledTask支持的调度器类 bx:schedule组件(HTTP 驱动的任务):用于创建/更新/删除/暂停/恢复/列出/运行任务的端点
对于丰富的进程内逻辑和任务回调,请使用调度器 DSL。对于简单的持久化 URL 触发器,请使用 bx:schedule。
Application.bx 集成
你可以直接在 Application.bx 中注册调度器类,以便它们在应用上下文中自动发现。
有关完整的描述符行为(应用发现、多应用隔离、生命周期),请参阅
application-descriptor。
class {
this.name = "MyApp"
// Auto-register scheduler classes for this application
this.schedulers = [
"schedulers.DailyMaintenance",
"schedulers.HourlyReports"
]
}
当调度器生命周期应由应用启动/关闭管理,而非通过临时调用 schedulerStart() 管理时,请使用此方式。
选项 1:调度器 DSL(代码工作负载推荐)
调度器类封装 BaseScheduler,并在 configure() 中以流畅方式注册任务。
class {
property name="scheduler"
property name="logger"
function configure() {
scheduler
.setSchedulerName( "reporting-scheduler" )
.setTimezone( "America/Chicago" )
scheduler.task( "daily-report", "reports" )
.call( () => generateDailyReport() )
.everyDayAt( "02:00" )
.onFailure( ( task, exception ) => {
logger.error( "Task #task.getName()# failed: #exception.message#" )
} )
}
}
注册和启动调度器类
// Start from class path (creates, configures, registers, and starts)
schedulerStart( className = "schedulers.ReportingScheduler", name = "reporting", force = true )
// Lookup / control
schedulerGet( "reporting" )
schedulerStats( "reporting" )
schedulerRestart( "reporting", force = false, timeout = 30 )
schedulerShutdown( "reporting", force = false, timeout = 30 )
选项 2:bx:schedule 组件(HTTP 驱动)
bx:schedule 会持久化任务定义(默认路径:${boxlang-home}/config/tasks.json),并执行定时 HTTP GET 请求。
bx:schedule action="create"
task="nightlyCleanup"
url="https://myapp.example/tasks/cleanup"
cronTime="0 2 * * *";
bx:schedule action="pause" task="nightlyCleanup";
bx:schedule action="run" task="nightlyCleanup";
bx:schedule action="delete" task="nightlyCleanup";
此方式适用于 Webhook、回调端点和运维探测。
调度器 BIF
核心调度器生命周期 BIF:
schedulerStart( className, name?, force=true )schedulerGet( name )schedulerGetAll()schedulerList()schedulerStats( name? )schedulerRestart( name, force=false, timeout=30 )schedulerShutdown( name, force=false, timeout=30 )
说明:
schedulerStart()会实例化 BoxLang 类,将其封装在BoxScheduler中,调用configure(),然后注册并启动它。schedulerRestart()和schedulerShutdown()会验证调度器是否存在;若不存在则抛出异常。
任务注册模式
使用有意义的名称和可选分组,以便清晰地进行运维管理。
scheduler.task( "cleanup-expired-sessions", "maintenance" )
.call( () => cleanupSessions() )
.every( 15, "minutes" )
scheduler.task( "send-weekly-digest", "notifications" )
.call( () => sendDigest() )
.everyWeekOn( "Monday", "08:30" )
注册时禁用,便于调试:
scheduler.xtask( "experimental-task", "debug" )
.call( () => runExperiment() )
.everyMinute()
常用频率 API
every( period, timeUnit )spacedDelay( delay, timeUnit )(无重叠模式)cron( expression )everySecond()、everyMinute()、everyHour()、everyHourAt( minute )everyDay()、everyDayAt( "HH:mm" )everyWeek()、everyWeekOn( day, time )everyMonth()、everyMonthOn( day, time )everyYear()、everyYearOn( month, day, time )onWeekdays( time )、onWeekends( time )
everyMonthOn( day ) 会在较短月份中将日期调整为当月最后一天(v1.18+),因此 everyMonthOn( 31 ) 在 2 月会运行一次,而不是每天运行。
服务器固定(集群,v1.18+)
当同一调度器部署到每个节点时,每个节点都会运行所有任务。调用 .onOneServer(),即可让每次执行只由一个节点运行。BoxLang 使用调度器的 cacheName 缓存作为分布式锁,因此请将其指向各服务器共享的缓存(例如通过 bx-redis 使用 Redis)。
task( "nightly-cleanup" )
.call( () => cleanupOldRecords() )
.everyDayAt( "02:00" )
.onOneServer()
调度器 API 支持的时间单位包括:days、hours、minutes、seconds、milliseconds、microseconds、nanoseconds。
Cron 支持
支持的格式:
- 5 字段 Unix:
minute hour day-of-month month day-of-week - 6 字段 Quartz:
second minute hour day-of-month month day-of-week
示例:
// Every day at 2:00 AM
scheduler.task( "nightly" )
.call( () => nightlyJob() )
.cron( "0 2 * * *" )
// Every weekday at 8:30:00 AM
scheduler.task( "weekday-digest" )
.call( () => digestJob() )
.cron( "0 30 8 * * MON-FRI" )
最佳实践
- 始终为调度器设置明确的
name和timezone。 - 使用描述性任务名称和逻辑分组。
- 保持任务主体精简;将繁重的扇出工作转移到异步执行器。
- 优先使用
onFailure钩子和集中式日志记录,以便观察运行情况。 - 未检查吞吐量前,避免设置过于密集的间隔。
- 如果任务的运行时间可能超过其间隔,请使用
spacedDelay()或防止重叠的模式。 - 对于必须在集群范围内只运行一次的任务,使用
.onOneServer()(v1.18+)。 - 使用 CLI 检查调度情况:
boxlang schedule和boxlang schedule --json(v1.18+)。
故障排查
- 找不到调度器:确认已调用
schedulerStart(),且schedulerList()包含该名称。 - 任务从未触发:检查时区、cron 表达式以及开始/结束约束。
- 重复运行/运行堆叠:使用间隔控制/防止重叠策略,而非严格的固定频率行为。
- 任务在每个节点上运行:添加
.onOneServer(),并使用共享的cacheName(v1.18+)。 - 静默失败:检查调度器日志输出和
schedulerStats()计数器(totalFailures、lastResult)。