使用 systemd-analyze calendar 预测下一次执行时间 —— OnCalendar 与 Persistent 的区别

Linux・CLI・DevOpsカテゴリを表すパンダのイラスト Linux・CLI・DevOps

关于本文
本文是通过利用生成式 AI 的自动生成流程创建的。我们查阅了 systemd-analyze、systemd.timer 和 systemd.time 的官方手册,并编写了一个以只读方式检查下一次启动时间的示例。目前尚未在目标 Ubuntu 系统上进行执行验证。

验证状态:📘 已查阅 systemd 官方手册,尚未在 Ubuntu 实机上验证

在 Ubuntu 中*.timer有时服务并未在预期的时间运行。常见的误解是认为日历表达式正确就等同于实际定时器已启用这一观点。

systemd-analyze calendar通过使用OnCalendar=,无需启用定时器,即可解析与Persistent、AccuracySec相同格式的表达式,并列出下一次预计执行的日期和时间。此外,分时区进行检查可以减少遗漏。

最小实验:尝试计算每 2 小时的时间

例如,如果希望在日本时间的 00:05、02:05、04:05、…、22:05 执行,日历表达式应编写如下。

[Timer]
OnCalendar=*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo
Persistent=false

这是一个配置示例。尚未启用服务或定时器。

请在 Ubuntu 中运行以下命令。

systemd-analyze calendar --iterations=8 \
  '*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo'

此操作不需要sudo,也不会启动 WordPress 等生产服务。它只是解析日期和时间语法,并计算接下来的 8 次触发计划。输出的年月日和星期几会根据执行时的不同而变化。

Original form: ... Asia/Tokyo
Normalized form: ...
Next elapse: (次の偶数時05分に相当する日時)
Iter. #2: (さらに2時間後)
...

※以上为显示项目的示例,并非实机日志的转录。

修改一处进行观察

我想确认的是,每小时整点(00分)与每两小时一次的区别。

# 毎時00分

systemd-analyze calendar --iterations=4 \
  '*-*-* *:00:00 Asia/Tokyo'

# 偶数時05分

systemd-analyze calendar --iterations=4 \
  '*-*-* 00,02,04,06,08,10,12,14,16,18,20,22:05:00 Asia/Tokyo'

两者的输出中Next elapse与Iter. #2之间的间隔。前者应该按大约1小时间隔计算,后者按大约2小时间隔计算。这样一来,无需运行实际服务,就能确认预期的计划是否已正确转化为表达式。

Daily-Code-Samples的脚本中,我保存了将这些确认步骤整合到一起的preview-calendar.sh。你可以将任意日历表达式作为参数传入。

bash preview-calendar.sh
bash preview-calendar.sh '*-*-* 08:30:00 Asia/Tokyo'

“计划时间正确”与“实际运行成功”的区别

要调查的内容确认对象可知晓的事项
日历表达式的语法systemd-analyze calendar下一次触发计划
定时器是否已注册并启用systemctl list-timers --all当前管理的定时器
Unit的定义systemctl cat 名前.timerOnCalendar和Persistent等设置
最近的服务执行结果systemctl status 名前.service当前的进程状态与最近一次执行
错误详情journalctl -u 名前.service服务日志

即使日历表达式正确,如果 timerinactive或disabled处于某种状态,通常也不会按计划自动执行。此外,即使定时器运行,如果服务本身失败,处理也不会完成。

接下来的操作是仅读取现有设置。请将调查对象替换为您自己管理的名称。

systemctl list-timers --all --no-pager
systemctl cat example.timer
systemctl show example.timer \
  -p ActiveState -p Unit -p NextElapseUSecRealtime -p LastTriggerUSec
journalctl -u example.service --no-pager -n 30

指定找不到的 Unit 并不合适。请在确认实际的 timer 名称后再进行替换。根据查看权限,有时可能无法读取部分 Journal。

将 Persistent 设为 true 会发生什么?

Persistent=true是一项设置,当基于 OnCalendar 的定时器在停止或未运行期间错过触发计划时,允许在重新启动等情况下进行追赶运行。

设置主要含义实务上的注意事项
Persistent=false不要设置为无条件补回停止期间的触发可以更容易地防止发布、计费处理等意外的延迟执行
Persistent=true允许追赶运行在停止期间错过的日历执行确认恢复后是否会发生意料之外的执行
AccuracySec触发时间的精度窗口有时可能并非刚好在预定时间

容易产生误解的是,Persistent=true最容易陷入的误区是认为“会把错过的部分一件一件全部重新执行”。这是无法保证的。定时器只是一种启动服务的机制,它不会管理待处理队列的数量或发布内容是否重复。

例如,如果每2小时发布一篇博客,千万不能因为服务器停机了12小时,就一口气把过去的6篇全部发布。应当在定时器中使用限制延迟触发的设置,并在应用层检查“是否仅限当天”以及“在此2小时时间段内最多1篇”。

当存在时区差异时

OnCalendar=*-*-* 08:30:00如果只写了这些,主机的时区设置就会产生影响。如果云服务器使用的是UTC时间,它将与在日本看到的08:30不一致。

timedatectl
date '+%Y-%m-%d %H:%M:%S %Z'
systemd-analyze calendar '*-*-* 08:30:00 Asia/Tokyo'

通过采用日历格式的写法Asia/Tokyo,可以明确时间的基准。但是,如果服务器的时钟同步状态本身就不准确,即使日历的解析正确,实际动作也会发生偏差。

AccuracySec与服务处理时间

OnCalendar即使指定了具体的时间,AccuracySec由于精度范围以及服务等待启动等原因,并不保证能与指定的秒数完全一致。不仅要排查常见的Linux性能问题,还要检查Unit的配置。

此外,相同的服务是否正在运行、服务执行需要多长时间,也是运维中的重要条件。即使定时器的计划是每2小时一次,如果应用的设计是无限期重试,也无法做到每2小时处理一次的上限。

将责任明确划分为:时间控制交由timer、对象有效性交由应用、执行结果交由日志或数据库,这样将更容易排查原因。

实务中需要确认的5个项目

  1. OnCalendar是否可以用systemd-analyze calendar进行评估。

  2. 是否明确了时区。

  3. timer本身是否有效,并且拥有下一次的计划执行时间。

  4. Persistent以及AccuracySec是否为预期行为?

  5. 是否核对过触发后的服务终止状态及日志?

按此顺序确认,即可区分“时间指定错误”、“定时器无效”、“服务异常终止”以及“实际业务处理量为0”等不同原因。

一手资料

文档信息

文章??
使用 systemd-analyze calendar 预测下一次执行时间 —— OnCalendar 与 Persistent 的区别
?布日期
更新日期
来源
https://papanda925.com/?p=18074&lang=zh

?可: ?于本站?有相??利的正文及原??表,除非?有?明,可依据 CC BY 4.0 使用。本文可能包含使用生成式AI?建或??的内容。若代??有?可声明,或?接的GitHub???定了?可,?代?以??可?准。引用内容、第三方?料、?片及商?不在本?可范?内。 使用政策

标题和URL已复制