当前位置:首页 > 文章列表 > 文章 > linux > systemd timer 替代 cron 的日历表达式配置

systemd timer 替代 cron 的日历表达式配置

来源:17golang原创 2026-10-04 01:14:07 0浏览 收藏

把 cron 任务迁移到 systemd timer,关键不是把五段 cron 表达式机械翻译成另一串字符,而是先把“执行什么”和“何时执行”拆开:.service 负责命令、账户、工作目录与失败状态,.timer 负责日历表达式、补跑、精度和错峰。这样任务既能被单独启动测试,也能通过 systemd 的状态与日志入口排查。

本文用一个每天 02:30 执行的备份脚本做最小示例。假设脚本位于 /usr/local/sbin/backup-app,由 backup 用户运行。正式配置前,请确认脚本无需交互输入,并且所有路径都使用绝对路径。

官方地址:https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html
日历语法:https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html

最小配方
  • 同名的 backup.timer 默认触发 backup.service,通常不必额外写 Unit=。
  • OnCalendar=*-*-* 02:30:00 表示每天本地时间 02:30。
  • Persistent=true 只对 OnCalendar 生效,用于补触发 timer 停用期间错过的日历任务。
  • 先用 systemd-analyze calendar 校验,再启用 timer。

先理解为什么要拆成两个 unit

cron 的一行同时装着时间和命令;systemd 则把两者分成独立 unit。backup.service 可以被手动执行,用来检查权限、环境与返回码;backup.timer 只负责在日历条件满足时激活它。官方手册说明,如果 timer 未显式配置 Unit=,它会默认激活与自己同名、仅后缀不同的 service。

例如 backup.timer 自动对应 backup.service。如果 timer 叫 nightly-backup.timer,service 也应叫 nightly-backup.service;只有确实要触发不同名称的 unit 时,才在 [Timer] 中写 Unit=other.service。

写出最小可用的 service 与 timer

先创建 /etc/systemd/system/backup.service。Type=oneshot 适合运行后退出的批处理任务。不要依赖交互式 shell 的 PATH、别名或当前目录;若脚本需要固定工作目录,应明确写 WorkingDirectory=。

# /etc/systemd/system/backup.service
[Unit]
Description=Backup application data

[Service]
Type=oneshot
User=backup
Group=backup
WorkingDirectory=/srv/app
ExecStart=/usr/local/sbin/backup-app

再创建 /etc/systemd/system/backup.timer:

# /etc/systemd/system/backup.timer
[Unit]
Description=Run application backup every day at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
AccuracySec=1min

[Install]
WantedBy=timers.target

OnCalendar 使用实时时钟和日历语法。未指定时区时,它按系统当前时区解释;需要固定时区时可以把 IANA 时区名写在表达式末尾,例如 *-*-* 02:30:00 Asia/Shanghai。不要在同一组服务器上有的机器依赖本地时区、有的机器写固定时区,否则同一 unit 的实际触发时刻会难以比较。

backup.timer、OnCalendar、Persistent、AccuracySec、backup.service、ExecStart 与 timers.target 的静态关系图
图1:systemd timer 日历任务单元关系;各连线表示配置依赖,不表示实际执行顺序。

先用 systemd-analyze calendar 校验表达式

systemd-analyze calendar 会解析并标准化日历表达式,同时计算下一次触发时间。它比仅凭肉眼判断更可靠,尤其适合包含星期范围、列表和步进值的表达式。

# 校验每天 02:30 的表达式,并查看标准化结果与下一次触发。
systemd-analyze calendar '*-*-* 02:30:00'

# 校验工作日 09:00。
systemd-analyze calendar 'Mon..Fri *-*-* 09:00:00'

# 校验每小时从第 2 分钟开始、每 15 分钟一次的步进表达式。
systemd-analyze calendar '*:02/15'

第三个表达式会被补全为完整日期和秒字段。若真正想要每小时的第 0、15、30、45 分钟,可写 *:00/15 并以本机解析结果为准。systemd 还提供 daily、weekly、monthly 等简写,但在团队配置中写出完整时间通常更容易审核。

需求OnCalendar 示例说明
每天 02:30*-*-* 02:30:00日期字段全匹配
周一至周五 09:00Mon..Fri *-*-* 09:00:00星期名称使用英文
每月 1 日 04:10*-*-01 04:10:00日期固定为 01
每小时每 15 分钟*:00/15先用 calendar 子命令确认标准化结果
每天上海时间 02:30*-*-* 02:30:00 Asia/Shanghai不随主机默认时区变化

Persistent、AccuracySec 与随机延迟不要混用概念

Persistent=true 会把 service 上一次由 timer 触发的时间保存到磁盘。timer 再次激活时,如果停用期间至少错过了一次计划,就立即补触发一次;它不会把错过的每个时间点逐个重放。该选项只对配置了 OnCalendar 的 timer 有效,默认值是 false。

AccuracySec 是触发精度窗口,默认值为 1 分钟。它允许 systemd 在指定时间之后的一段窗口内合并唤醒,以减少无谓的 CPU 唤醒;若任务必须尽量靠近给定时刻,可以缩小该值,例如 AccuracySec=1s。没必要为普通夜间任务设置极小值。

RandomizedDelaySec 则主动在 0 到指定值之间增加随机延迟,用于让同一时间配置的大量任务错峰。它的默认值是 0。比如多台机器都在凌晨上传备份,可以加入:

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
AccuracySec=1s
RandomizedDelaySec=20min

这里先增加随机延迟,再受 AccuracySec 的合并窗口影响。前者是削峰,后者是允许合并唤醒,两者目标不同。若配置了随机延迟,Persistent=true 的补触发也仍会受该延迟约束。

加载、启用并查看下一次计划

配置写完后先让 manager 重新读取 unit,再启用 timer。通常只启用 .timer,不需要 enable 同名 oneshot service。

# 重新读取新增或修改的 unit 文件。
sudo systemctl daemon-reload

# 立即启动 timer,并让它在后续开机时进入 timers.target。
sudo systemctl enable --now backup.timer

# 查看该 timer 的最近触发与下一次计划。
systemctl list-timers --all backup.timer

# 查看 timer 当前状态及最后一次调度信息。
systemctl status backup.timer

list-timers 中的 NEXT 是下一次触发时间,LAST 是最近一次触发时间;它们确认的是“计划是否存在”。任务本身是否成功,还要看 service 状态和日志。

OnCalendar、systemd-analyze calendar、systemctl list-timers、Next、Last 与 journalctl 的静态对应关系图
图2:表达式、计划与日志的核对入口;定义是否正确和任务是否成功需要分别确认。

把执行结果和调度结果分开排查

在等待真实触发时间之前,可以先手动启动 service。这不会修改 timer 的日历表达式,适合确认脚本权限、路径和退出码。

# 单独测试执行单元;失败时命令返回非零状态。
sudo systemctl start backup.service

# 查看最近一次 service 状态。
systemctl status backup.service

# 查看本次开机以来该任务的日志。
journalctl -u backup.service -b --no-pager

# 查看 timer 自身的调度日志,不等同于脚本输出。
journalctl -u backup.timer -b --no-pager

若 backup.timer 显示 active 且有 NEXT,但 service 从未运行,先确认系统时间、时区与表达式;带 OnCalendar 的 timer 会自动排在 time-sync.target 之后,但缺少可靠实时时钟的设备仍应确保时钟同步服务真正完成校时。若 service 已被触发却失败,则回到 service 日志检查用户权限、工作目录、环境变量和脚本返回码。

从 cron 迁移时最容易踩的边界

现象原因处理
timer 激活但任务找不到命令脚本依赖交互式 shell 的 PATH在脚本和 ExecStart 中使用绝对路径,显式配置 Environment
机器开机后立刻执行Persistent=true 发现停机期间错过计划这是补跑语义;不需要补跑时设为 false
不是严格在整点执行AccuracySec 默认允许 1 分钟窗口按业务需要缩小,而非一律设成 1us
多台机器同时压垮后端所有 timer 使用相同计划且无错峰使用 RandomizedDelaySec,必要时再研究稳定随机偏移
修改 unit 后没有变化未执行 daemon-reload重新加载后 restart timer
只看 timer 误判任务成功timer 只负责激活 service同时查看 backup.service 状态与 journal

修改计划后的完整收尾

编辑已有 timer 后,不要重复 enable;重新加载并重启 timer 即可。再次运行 calendar 校验和 list-timers,可以同时覆盖“表达式能否解析”和“manager 是否已经采用新计划”两个问题。

# 修改 backup.timer 后重新加载并重启调度单元。
sudo systemctl daemon-reload
sudo systemctl restart backup.timer

# 重新检查 unit 内容和下一次计划。
systemctl cat backup.timer
systemctl list-timers --all backup.timer

如果只是每天、每周、每月这类日历计划,OnCalendar 加同名 service 已能替代大多数 cron 用法;若需求是“开机后延迟多久”“上次任务完成后再等多久”,应改用 OnBootSec、OnUnitActiveSec 或 OnUnitInactiveSec 等单调计时器,而不是继续堆叠日历表达式。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
照妖镜随机数工具怎么用?趣味决策与结果边界说明照妖镜随机数工具怎么用?趣味决策与结果边界说明
上一篇
照妖镜随机数工具怎么用?趣味决策与结果边界说明
Go json/v2 与 json v1 迁移时的字段兼容清单
下一篇
Go json/v2 与 json v1 迁移时的字段兼容清单
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    318次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    375次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    372次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    337次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    163次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码