| name | hai-scheduler |
| description | 使用 @h-ai/scheduler 进行统一定时任务管理、任务持久化、手工触发、触发来源审计、全局生命周期回调与执行日志查询;当需求涉及 cron 调度、JS 函数字符串任务、API 任务、分布式锁或任务事件回调时使用。 |
hai-scheduler
能力契约
| 项目 | 契约 |
|---|
| 能力 | 使用 @h-ai/scheduler 进行统一定时任务管理、任务持久化、手工触发、触发来源审计、全局生命周期回调与执行日志查询;当需求涉及 cron 调度、JS 函数字符串任务、API 任务、分布式锁或任务事件回调时使用。 |
| 适用场景 | 当任务与 hai-scheduler 的能力描述匹配,并且需要遵循本 Skill 的流程和边界时 |
| 输入 | 模块配置、类型化业务参数、依赖初始化状态和目标运行环境 |
| 输出 | 符合模块公共 API 的实现或示例;业务结果使用 HaiResult,并同步必要测试与文档 |
| 限制 | 遵守 init → use → close 生命周期与运行环境边界;不绕过类型、授权、输入校验或敏感信息保护 |
@h-ai/scheduler 使用统一任务模型管理 API / JS / Hook 三类执行路径,支持持久化、手工触发来源记录、分布式锁与全局生命周期回调。
运行环境
⚠️ 服务端模块(Node.js only)。 浏览器端通过 API 端点触发 scheduler.trigger() 或查询任务日志。
依赖
| 模块 | 用途 | 是否必需 | 初始化要求 |
|---|
@h-ai/reldb | 任务定义与执行日志持久化 | enableDb: true 时必需 | 需在 scheduler.init() 前初始化 |
@h-ai/cache | 分布式锁 | 可选 | 初始化后自动启用 |
使用步骤
1. 初始化
import { cache } from '@h-ai/cache'
import { core } from '@h-ai/core'
import { reldb } from '@h-ai/reldb'
import { scheduler } from '@h-ai/scheduler'
await reldb.init({ type: 'sqlite', database: './scheduler.db' })
await cache.init({ type: 'memory' })
await scheduler.init({
enableDb: true,
maxLogs: 1000,
retentionDays: 30,
hooks: {
onTaskStart(event) {
core.logger.info('Task started', { taskId: event.task.id, trigger: event.trigger })
},
onTaskInterrupted(event) {
core.logger.warn('Task interrupted', { taskId: event.task.id, reason: event.reason })
},
onTaskFinish(event) {
core.logger.info('Task finished', { status: event.log.status })
},
},
})
2. 注册任务
await scheduler.register({
id: 'health-check',
name: '健康检查',
description: '每 5 分钟巡检一次接口健康状态',
cron: '*/5 * * * *',
params: { channel: 'ops' },
retry: { maxAttempts: 3, backoffMs: [1000, 5000] },
handler: {
kind: 'api',
url: 'https://api.example.com/health',
method: 'GET',
},
})
await scheduler.register({
id: 'cleanup',
name: '清理过期数据',
description: '夜间单次清理任务',
cron: '0 2 * * *',
deleteAfterRun: true,
params: { source: 'nightly' },
handler: {
kind: 'js',
code: '(context) => ({ taskId: context.taskId, params: context.params })',
},
})
⚠️ 安全警示:kind: 'js' 仅允许受信任的服务端代码。当前实现使用 Node.js vm 便捷执行,不是安全沙箱;禁止把用户、租户或运营后台自由输入的 JS 字符串直接注册为任务。需要可配置执行逻辑时,优先改用 kind: 'api' 或 hooks.onTaskExecute。
3. 使用全局 execute hook 处理无 handler 任务
await scheduler.setHooks({
async onTaskExecute(event) {
return { via: 'hook', source: event.context.trigger.source }
},
})
await scheduler.register({
id: 'hook-task',
name: 'Hook 任务',
cron: '* * * * *',
})
4. 手工触发与日志查询
const result = await scheduler.trigger('cleanup', { source: 'admin-console' })
const logs = await scheduler.getLogs({
taskId: 'cleanup',
triggerType: 'manual',
triggerSource: 'admin-console',
startedAfter: Date.now() - 24 * 60 * 60 * 1000,
startedBefore: Date.now(),
pagination: { page: 1, pageSize: 20 },
})
核心 API
| 方法 / 属性 | 签名 | 说明 |
|---|
init | (config?) => Promise<HaiResult<void>> | 初始化调度器 |
register | (task) => Promise<HaiResult<void>> | 注册统一任务模型 |
updateTask | (taskId, updates) => Promise<HaiResult<void>> | 更新 cron / params / handler |
register 扩展字段 | description / deleteAfterRun / retry | 支持任务描述、一次性任务、失败重试策略 |
trigger | (taskId, { source? }) => Promise<HaiResult<TaskExecutionLog>> | 手工触发并记录来源 |
getLogs | (options?) => Promise<HaiResult<PaginatedResult<TaskExecutionLog>>> | 支持按 trigger + startedAfter/startedBefore 过滤日志 |
setHooks | (hooks) => HaiResult<void> | 设置全局生命周期回调 |
clearHooks | () => HaiResult<void> | 清空全局生命周期回调 |
start / stop | () => HaiResult<void> | 启动 / 停止调度 |
close | () => Promise<void> | 关闭调度器 |
常见模式
持久化 JS 任务
await scheduler.init({ enableDb: true })
await scheduler.register({
id: 'persisted-js',
name: '持久化 JS 任务',
cron: '*/10 * * * *',
handler: {
kind: 'js',
code: '(context) => ({ taskId: context.taskId })',
},
})
手工触发来源审计
await scheduler.trigger('cleanup', { source: 'admin-console' })
await scheduler.trigger('cleanup', { source: 'cli' })
const adminLogs = await scheduler.getLogs({ triggerSource: 'admin-console' })
分布式锁
await cache.init({ type: 'redis', host: 'localhost', port: 6379 })
await reldb.init({ type: 'sqlite', database: './scheduler.db' })
await scheduler.init({
enableDb: true,
maxLogs: 500,
retentionDays: 14,
lockExpireMs: 300000,
nodeId: 'node-1',
})
错误码 — HaiSchedulerError
| 错误码 | code | 说明 |
|---|
HaiSchedulerError.NOT_INITIALIZED | hai:scheduler:010 | 未初始化 |
HaiSchedulerError.INIT_FAILED | hai:scheduler:011 | 初始化失败 |
HaiSchedulerError.CONFIG_ERROR | hai:scheduler:012 | 配置错误 |
HaiSchedulerError.TASK_NOT_FOUND | hai:scheduler:020 | 任务不存在 |
HaiSchedulerError.TASK_ALREADY_EXISTS | hai:scheduler:021 | 任务已存在 |
HaiSchedulerError.INVALID_CRON | hai:scheduler:022 | Cron 表达式无效 |
HaiSchedulerError.EXECUTION_FAILED | hai:scheduler:023 | 执行失败 |
HaiSchedulerError.JS_EXECUTION_FAILED | hai:scheduler:024 | JS 执行失败 |
HaiSchedulerError.API_EXECUTION_FAILED | hai:scheduler:025 | API 执行失败 |
HaiSchedulerError.DB_SAVE_FAILED | hai:scheduler:026 | DB 保存失败 |
HaiSchedulerError.ALREADY_RUNNING | hai:scheduler:027 | 已在运行 |
HaiSchedulerError.NOT_RUNNING | hai:scheduler:028 | 未在运行 |
HaiSchedulerError.LOCK_ACQUIRE_FAILED | hai:scheduler:029 | 锁获取失败 |
HaiSchedulerError.JS_COMPILE_FAILED | hai:scheduler:030 | JS 编译失败 |
HaiSchedulerError.HOOK_EXECUTION_FAILED | hai:scheduler:031 | Hook 执行失败 |