花拾录
← 返回知识库

systemd 定时器配了却不触发:间隔式触发方式产生不了下一次时间

云计算 / 运维导入2026/09/220 阅读0 评论

你写了一个 systemd 定时器,想让它每 15 分钟跑一次。你用了"开机后多久"加"上次激活后多久"这两种触发方式,语法检查通过,服务也 reload 过了。可时间表里"下一次触发时间"那一栏显示为一个 -(空),任务就是不动。

现象

关键证据来自 systemctl list-timers:

systemctl list-timers mytask.timer

输出里的 NEXT 一栏(下一次触发时间)显示为 -,也就是说下次触发时间算不出来。定时器状态是 active (waiting),看着像在等,可实际上永远等不到。

根因

问题出在用错了触发方式,并且把它们组合了起来。

systemd 定时器有两类触发方式:

  • 间隔式(monotonic):OnActiveSec=、OnBootSec=、OnStartupSec=、OnUnitActiveSec=、OnUnitInactiveSec=。它们表示"相对于某个时间点之后多久"——比如"开机后 5 分钟""上次激活后 15 分钟"。
  • 日历式(realtime):OnCalendar=。它表示"在符合这个日历规则的时刻"——比如每小时的第 3 分、每天的 03:30。

你用的 OnBootSec=(开机后多久)和 OnUnitActiveSec=(上次激活后多久)都是间隔式。理论上前者提供一个起点、后者提供"之后就每 15 分钟一次"。

但问题在于:这种"间隔式"的组合,在该环境下不可靠,组合起来产生不了下一次触发时间。

具体地,间隔式的触发时间需要有一个"锚点"来递推——OnUnitActiveSec 要靠"上次激活时刻"来推下一次,而如果锚点没有正确建立(比如系统状态、时钟跳变、或这个组合本身在该版本上的行为不支持递推),systemd 就算不出下一个时刻,NEXT 就只能是 -。任务因此永远不会被触发,但定时器看起来又是 active 的,极具迷惑性。

解决

改用日历式表达式。

日历式的语义是"在符合规则的时钟时刻触发",它不依赖"上次激活"这个锚点,因此稳定得多。要表达"每 15 分钟一次",可以这样写:

# mytask.timer
[Unit]
Description=Run mytask every 15 minutes

[Timer]
# 每小时的第 3、18、33、48 分触发(即每隔 15 分钟,错开 3 分钟)
OnCalendar=*:03/15
# 如果错过了触发时间(比如关机中),开机后补跑一次
Persistent=true
# 这个定时器关联的服务
Unit=mytask.service

[Install]
WantedBy=timers.target

*:03/15 的含义是:每小时的第 3 分钟起,每 15 分钟触发一次 → 第 3、18、33、48 分。用 03 而不是 00 只是为了让触发时间错开整点,避免和别的整点任务挤在一起;你要用 *:00/15(即 0、15、30、45 分)也没问题。

改完:

systemctl daemon-reload
systemctl restart mytask.timer
systemctl list-timers mytask.timer

这次 NEXT 一栏应该显示出一个具体的未来时刻,而不是 -。这就对了。

顺便,配套的 service 可以写得简单:

# mytask.service
[Unit]
Description=My task

[Service]
Type=oneshot
ExecStart=/usr/local/bin/mytask.sh

延伸与预防

这条坑给出两条值得记住的经验。

其一:周期性任务优先用"日历式",而不是"间隔式"叠加。

间隔式的设计初衷是"相对于系统启动/激活的间隔",适合"开机后 5 分钟做一次检查"这种不关心具体时刻的场景。而"每 15 分钟""每天凌晨 3 点"这种关心时钟时刻的需求,用 OnCalendar 表达最自然、也最稳。两者别混着用来拼一个周期。

其二:判断定时器"是不是真的会跑",看 NEXT 而不是看状态。

active (waiting) 只说明"定时器被启用了",不代表"它算得出下次触发时间"。真正可靠的判据是 systemctl list-timers 里那个具体的 NEXT 时刻——它是空 (-) 就说明排不上,一定有问题。这个习惯能让你在"任务莫名不跑"时,一眼定位到是定时器本身就没排上,而不是去服务脚本里找 bug。

最后,别忘了 Persistent=true:对"每天/每周期该跑一次、但机器可能关机错过"的任务,它能在开机后补跑一次错过的触发。很多"任务偶尔少跑一次"的怪象,加上这一行就解决了。

评论(0)

  • 还没有评论,来抢沙发~

相关文章