服务生命周期
启动流程(service/ops.ts::start)
- 加载存储:读取
jobs.json+jobs-state.json,合并状态 - 处理中断运行:检查
runningAtMs字段,标记为失败(“cron: job interrupted by gateway restart”),增加consecutiveErrors - 追赶错过任务:识别
nextRunAtMs < nowMs的任务,按优先级排序,限制并发(默认 5 个),错开执行(默认 5s 间隔) - 启动定时器:计算下一个到期任务,设置定时器
定时器循环(service/timer.ts::armTimer)
armTimer()
→ 找到最近到期的任务
→ setTimeout(min(nextRunAtMs - now, 60s))
→ 触发时:executeJobCoreWithTimeout()
→ 完成后:重新 armTimer()
最大定时器延迟 60s,防止长时间睡眠导致任务延迟。
执行引擎(service/timer.ts)
executeJobCoreWithTimeout
带三层超时的任务执行:
| 阶段 | 超时 | 说明 |
|---|---|---|
| Setup | 60s(CRON_AGENT_SETUP_WATCHDOG_MS) | Agent 初始化 |
| Pre-execution | 60s(CRON_AGENT_PRE_EXECUTION_WATCHDOG_MS) | 执行前准备 |
| Execution | 5m(DEFAULT_JOB_TIMEOUT_MS) | 实际执行 |
| Cleanup guard | 20s(CRON_TIMEOUT_CLEANUP_GUARD_MS) | 超时后清理 |
支持 AbortSignal 中断。
applyJobResult
执行完成后:
- 更新
lastRunStatus、lastRunAtMs、lastDurationMs - 更新诊断信息(
lastDiagnostics) - 处理错误退避(更新
nextRunAtMs) - 触发失败告警(满足阈值时)
- 处理交付(announce/webhook)
- 清理会话(
deleteAfterRun)
任务管理(service/jobs.ts)
关键函数
createJob(input) // 创建任务,生成 ID 和初始状态
applyJobPatch(job, patch) // 应用补丁更新
computeJobNextRunAtMs(job, nowMs) // 计算下次运行时间(含错开)
isJobDue(job, nowMs) // 检查是否到期
isJobEnabled(job) // 检查是否启用
recomputeNextRuns(state) // 重新计算所有任务的下次运行时间任务到期判断
isJobDue(job, nowMs):
job.enabled
&& job.state.nextRunAtMs !== undefined
&& job.state.nextRunAtMs <= nowMs
&& job.state.runningAtMs === undefined // 未在运行并发控制(service/locked.ts)
使用 locked() 函数保护关键操作,防止并发修改存储:
// 所有写操作都通过 locked() 串行化
await locked(state, async () => {
// 修改 state.jobs
// 保存到磁盘
})读操作使用 skipRecompute 标志避免副作用。
持久化存储(service/store.ts)
存储架构
| 文件 | 内容 | 写入频率 |
|---|---|---|
jobs.json | 任务配置(不含运行时状态) | 任务增删改时 |
jobs-state.json | 运行时状态 | 每次执行后 |
分离存储的优势:
- 减少写入冲突(配置和状态独立更新)
- 配置文件更稳定,便于备份和版本控制
- 状态文件高频写入不影响配置
原子写入
write(tmpFile)
→ rename(tmpFile, targetFile) // 原子操作
防止写入中途崩溃导致文件损坏。
迁移逻辑
检测 jobs.json 中的内联状态(旧格式),自动迁移到 jobs-state.json:
- 读取
jobs.json,检测是否有内联state字段 - 提取状态到
jobs-state.json - 后续只使用分离存储
缓存优化
序列化缓存:避免重复 JSON.stringify,仅在数据变化时重新序列化。
会话清理(session-reaper.ts)
清理策略
- 保留期:24 小时(
DEFAULT_RETENTION_MS) - 最小扫描间隔:5 分钟(
MIN_SWEEP_INTERVAL_MS) - 清理目标:
cron:<jobId>:run:<uuid>格式的临时会话 - 保留:基础会话
cron:<jobId>
清理流程
- 加载会话存储
- 识别过期的 cron 运行会话(
createdAt < now - 24h) - 删除会话记录
- 归档和清理转录文件
诊断与可观测性
CronRunDiagnostics
type CronRunDiagnostics = {
entries: Array<{
source: string
severity: "info" | "warn" | "error"
message: string
}>
summary?: string
}限制:最多 10 条(MAX_DIAGNOSTIC_ENTRIES),每条最多 1000 字符,摘要最多 2000 字符。
active-jobs.ts
追踪当前正在运行的任务,用于:
- 防止重复执行
- 提供运行状态查询
- 超时检测
相关页面
- cron-overview — 模块总览
- cron-types — 数据结构
- cron-isolated-agent — 隔离 Agent 执行
- cron-delivery — 交付系统