systemd timer OnCalendar 延迟几小时的 accuracy / randomizeddelay 配置

1次阅读

oncalendar 触发延迟主因是 randomizeddelaysec 默认1小时叠加唤醒补偿延迟,禁用需设 randomizeddelaysec=0 并配 accuracysec=1min;persistent=true 可补休眠错失的单次触发,但 weekly 语法实际等价于 mon,thu 且不支持 persistent。

systemd timer OnCalendar 延迟几小时的 accuracy / randomizeddelay 配置

OnCalendar 触发时间比预期晚几小时,是 accuracy 设置没生效?

不是 accuracy 没生效,而是 systemd 默认启用了 RandomizedDelaySec(默认 1 小时),且该延迟会叠加在 OnCalendar 基础上——哪怕你只写了 OnCalendar=hourly,实际触发也可能在整点后 0~3600 秒内随机漂移。更隐蔽的是:如果系统刚启动或从休眠恢复,systemd 还会额外施加 up to 1 小时的“唤醒补偿延迟”,合起来就可能晚 2 小时。

实操建议:

  • 确认是否真被随机化影响:systemctl show <service-name>.timer | grep -E "(Accuracy|Randomized)"</service-name>,检查 AccuracySecRandomizedDelaySec 实际值
  • 禁用随机延迟:在 timer 单元文件中显式写 RandomizedDelaySec=0(不能留空或注释掉)
  • 若需高精度(如分钟级同步),必须同时设 AccuracySec=1min,否则 systemd 仍可能把执行窗口放宽到默认 1h
  • 注意:修改后要 systemctl daemon-reload + systemctl restart <name>.timer</name>,仅 reload 不重启 timer 不会重载 RandomizedDelaySec

RandomizedDelaySec=0 之后还是不准?检查系统时钟与 suspend 行为

即使关了随机延迟,真实触发时间仍可能偏移几十秒到几小时——常见于笔记本或虚拟机:系统休眠后唤醒,systemd timer 不会“补发”错过的触发,而是等下一个自然周期;更糟的是,如果 OnCalendar 使用了 *-*-* 02:00:00 这类固定时间,而系统在凌晨 2 点关机/休眠,这次触发就永久丢失。

实操建议:

  • systemctl list-timers --all 查看下次触发时间(Next column),对比当前系统时间,确认是否真延迟,还是单纯“错过一次”
  • 避免依赖绝对时间:改用 OnBootSec=1hOnUnitActiveSec=1h,它们不依赖系统时钟对齐,适合后台轮询类任务
  • 若必须用 OnCalendar 且机器常休眠,加 Persistent=true ——它会让 timer 在唤醒后立即补跑一次错过的触发(但仅限最近一次,不会累积)
  • 检查 NTP 同步状态:timedatectl status,若 System clock synchronized: noOnCalendar 解析会出错(比如把 UTC 当本地时间算)

accuracy=1s 和 accuracy=1min 对资源和触发行为的实际影响

AccuracySec 不是“精度承诺”,而是 systemd 主动等待的“容忍窗口”。设太小(如 1s)会让 systemd 每秒检查一次时钟,增加唤醒频率和 CPU 开销;设太大(如 1h)则可能让本该 02:00 执行的任务拖到 02:59 才运行——尤其当系统负载高、timer 被调度延迟时,实际偏差会接近这个值。

实操建议:

  • 普通日志轮转、备份任务,AccuracySec=1min 安全且省电;实时性要求高的监控拉取,可压到 10s,但别盲目设 1s
  • AccuracySec 必须配合 RandomizedDelaySec=0 才有效,否则随机延迟会覆盖你的精度设置
  • 注意单位:只接受秒(30s)、分(2min)、时(1h),不支持 ms 或小数
  • 值越小,systemd 越频繁地从 idle 状态唤醒,对电池设备影响明显——systemd-analyze blame 可查 timer 唤醒次数

OnCalendar=weekly 和 OnCalendar=Mon *-*-* 02:00:00 的行为差异

表面都是“每周一凌晨 2 点”,但 weekly 是语法糖,等价于 Mon,Thu *-*-* 00:00:00(systemd 文档明确写死为周一+周四),而 Mon *-*-* 02:00:00 才是真正只在周一 2 点触发。更关键的是:两者对 Persistent 和错失触发的处理逻辑不同。

实操建议:

  • 永远用显式格式(如 Mon *-*-* 02:00:00)替代 weekly,避免语义误解
  • Persistent=trueweekly 无效——它只补最近一次错过的触发,但 weekly 每次触发都算“新周期”,补的可能是三天前的周一,而非刚错过的那个
  • 跨时区部署时,OnCalendar 默认按系统本地时区解析;若需 UTC,必须写 OnCalendar=Mon *-*-* 02:00:00 UTC,否则夏令时切换时可能漏掉或重复执行
  • 测试用 systemctl trigger <name>.timer</name> 不会模拟 OnCalendar 逻辑,要用 systemctl start <name>.timer</name> 手动触发验证

真正难调的不是参数本身,而是 timer 行为隐含的“上下文依赖”:系统是否休眠、NTP 是否同步、时区是否设对、甚至 systemd 版本对 Persistent 的实现差异——这些不会报错,只会让触发时间悄悄漂移几个小时。

text=ZqhQzanResources