使用 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 中刪除它們。

相關內容