Hotdry.

Article

systemd Timer 替代 Cron:持久化触发、日历表达式与依赖编排的工程实践

从 cron 迁移到 systemd timer,掌握 Persistent 补执行、OnCalendar 表达式语法与服务依赖编排的落地参数。

2026-06-02systems

Linux 定时任务的传统方案 cron 已服役数十年,其简洁的五段式语法(分 时 日 月 周)在简单场景下依然有效。然而,当系统需要处理 missed runs(错过执行)、服务依赖链、集中化日志与故障恢复时,cron 的局限性逐渐显现。systemd timer 作为现代替代方案,通过单元化设计、Persistent 持久化机制与声明式日历表达式,为生产环境提供了更可靠的定时任务编排能力。

为何从 cron 迁移

cron 的核心问题在于状态隔离与故障恢复。当系统在预定执行时间处于关机状态,该次任务将被永久跳过,除非业务脚本自行实现幂等与补偿逻辑。此外,cron 任务运行在最小化环境中,缺乏对系统服务的显式依赖声明,导致任务可能在数据库、网络或其他依赖未就绪时启动。

systemd timer 将定时触发逻辑(timer 单元)与任务执行体(service 单元)分离,每个单元拥有独立的配置、日志与生命周期管理。这种解耦设计使得定时任务可以复用 systemd 生态的全部能力:资源限制(CPU / 内存 / IO)、沙箱隔离(PrivateTmp/NoNewPrivileges)、依赖编排(After/Requires/Wants)以及集中式日志(journald)。

Persistent:错过触发的补执行策略

Persistent 是 systemd timer 最具生产力的特性之一。当配置 Persistent=true 时,systemd 会记录上次触发时间戳;若系统在下一次预定触发时刻处于离线状态,启动后会立即补执行错过的任务。这一机制对数据备份、报表生成、日志轮转等不可跳过的任务至关重要。

启用 Persistent 需注意两个工程细节。第一,业务脚本必须具备幂等性 —— 同一任务被多次执行不应产生重复副作用。第二,设置合理的 RandomizedDelaySec(随机延迟)以避免所有补执行任务在系统启动时集中爆发,造成资源争抢。例如,配置 RandomizedDelaySec=300 可在 0-300 秒范围内随机分散启动压力。

OnCalendar:从五段式到声明式日历表达式

systemd 的日历表达式语法 OnCalendar 远比 cron 的五段式灵活。基础格式遵循 星期 年-月-日 时:分:秒 的层级结构,支持通配符与范围语法:

  • 每日凌晨两点:OnCalendar=*-*-* 02:00:00 或简写 OnCalendar=daily
  • 工作日朝九晚六:OnCalendar=Mon..Fri *-*-* 09:00:00OnCalendar=Mon..Fri *-*-* 18:00:00
  • 每十五分钟:OnCalendar=*:0/15
  • 每月首日:OnCalendar=*-*-01 03:00:00
  • 带时区指定:OnCalendar=*-*-* 02:00:00 Asia/Shanghai

验证表达式正确性的工具是 systemd-analyze calendar。执行 systemd-analyze calendar "Mon..Fri 09:00" 可即时查看下一次触发时间,避免配置错误导致任务静默失败。ArchWiki 指出,OnCalendar 支持在同一 timer 单元中声明多个触发时刻,满足复杂调度需求。

依赖编排:服务单元的启动顺序与条件控制

timer 单元通过标准 systemd 依赖指令与 service 单元协同。常用配置包括:

  • After=network-online.target:确保网络就绪后触发
  • Requires=postgresql.service:数据库服务异常时跳过任务
  • OnFailure=notify.service:任务失败时调用通知服务

这种编排能力使定时任务成为系统服务拓扑的一等公民。例如,数据备份任务可声明 After=backup-storage.mount,确保存储挂载完成后再执行;结合 ConditionPathExists=/data/ready 可在标记文件存在时才触发,实现与上游数据管道的协调。

工程实践:验证、监控与迁移路径

迁移 cron 任务至 systemd timer 的推荐路径是渐进式:先迁移关键任务验证稳定性,再逐步替换剩余任务。每套 timer/service 配置应遵循以下检查清单:

  1. 语法验证:使用 systemd-analyze verify 检查单元文件语法
  2. 日历验证:使用 systemd-analyze calendar 确认触发时刻符合预期
  3. 手动触发:通过 systemctl start <service> 验证任务逻辑正确性
  4. 状态监控systemctl status <timer> 查看下次触发时间与上次执行结果
  5. 日志审计journalctl -u <service> 集中查看标准输出与错误输出

对于遗留的 cron 任务,可保留 /etc/cron.d 中的简单维护脚本,但将关键业务管道迁移至 timer 单元。这种混合架构兼顾了简单任务的维护便利与关键任务的可靠性需求。

总结

systemd timer 通过 Persistent 机制解决 cron 的 missed runs 问题,以声明式 OnCalendar 表达式提供更直观的调度语义,并借助 systemd 的依赖系统实现服务编排。这些特性使定时任务从「按时执行脚本」升级为「可观测、可编排、可恢复的系统组件」。对于运行 systemd 的现代 Linux 发行版,timer 单元已成为定时任务管理的工程默认。


参考来源

systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com