使用 systemd 安排命令在特定时间戳运行

使用 systemd 安排命令在特定时间戳运行

我想安排一个命令在特定时间运行,由 Unix 时间戳标识。看起来这可以通过 systemd 来实现systemd-run,但是它是如何工作的呢?如果在调度命令时机器断电或暂停,那么调度的命令会发生什么情况?

at相关问题:使用from做同样的事情atd(需要将时间戳解析回日期):是否可以使用 at 命令安排作业在给定时间戳运行?

答案1

systemd-run可以安排命令在特定时间运行,只要

  • 系统在此之前不会断电,因为它会将瞬态计时器和服务文件写入 /run,该文件在重新启动时会被清除,并且
  • 系统在该特定时间内不会暂停,除非您使用“WakeSystem”选项(见下文)。

有关重新启动持久选项,请参阅下文。

一个简单的例子systemd-run

# generate an arbitrary timestamp, in seconds-since-the-epoch
timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
  --timer-property=AccuracySec=1us \
  touch /tmp/done

systemd-run使用自纪元以来的秒数时间戳的重要部分是:

  • 使用--on-calendar
  • 在这里,使用 GNU date 将纪元时间戳以来的秒数转换为systemd-run可以理解的格式。您可以自己输入或转换时间戳,只要结果在OnCalendar 可以理解的格式

OnCalendar 的当前文档表明它直接支持自纪元时间戳以来的秒数输入。添加了“@秒”支持系统版本 234(在该页面中搜索该文件src/basic/calendarspec.c提交 d80e5b7。您的 systemd 版本可能早于此更改;举些例子:

  • RHEL 7从systemd 208开始,后来升级到版本219; RHEL 8 使用版本 239 (参考)。
  • Debian 8 使用版本 215,Debian 9 使用版本 232,Debian 10 使用版本 241(参考)。
  • Ubuntu 16.04 LTS 的版本为 229,Ubuntu 17.10 的版本为 234,Ubuntu 18.04 LTS 的版本为 237(参考)。

使用足够新的 systemd 版本,您可以使用以下调用:

timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "@${timestamp}" \
  --timer-property=AccuracySec=1us \
  touch /tmp/done

我还展示了一个AccuracySec 的计时器属性,默认为 1 分钟,您应该根据文档调整其值:

为了优化功耗,请确保将该值设置得尽可能高并根据需要设置得尽可能低。

我还没有测试过它,但还有一个名为的计时器选项WakeSystem

使系统从挂起状态恢复(如果系统处于挂起状态且系统支持此操作)。请注意,此选项仅确保系统在适当的时间恢复,而不会在任何要完成的工作完成后再次暂停系统。

您可以将其集成到上面,如下所示:

timestamp=$(date -d 'now + 42 seconds' +%s)
systemd-run --on-calendar "$(date -d @"$timestamp" +'%F %T')" \
  --timer-property=AccuracySec=1us \
  --timer-property=WakeSystem=true \
  touch /tmp/done

要求 systemd 在某个时间运行一个命令,其方式重启后仍然存在,并且独立于任何特定的登录会话,您需要将计时器和服务单元文件放在/etc/systemd/system/./etc/systemd/system 是存储本地配置的位置对于系统。

示例计时器文件如下:

[Timer]
AccuracySec=1us
[Unit]
Description=2020-01-22 09:50:00 timer
[Timer]
OnCalendar=2020-01-22 09:50:00

示例服务文件是:

[Unit]
Description=my 2020-01-22 09:50:00 service
[Service]
ExecStart=
ExecStart=@/usr/bin/bash "/usr/bin/bash" "-c" "echo 2020-01-22 09:50:00 timer and service ran > /tmp/done"

然后,您可以通过重新加载文件来通知 systemd 有关这些文件的信息:

systemctl daemon-reload

...然后启用计时器:

systemctl enable foo.timer

...然后启动计时器:

systemctl start foo.timer

一旦过期的计时器和服务单元的时间过去,您可能需要定期从 /etc/systemd/system 中删除它们。

相关内容