用於調度任務的 systemd 定時器
systemd 提供定時器有一段時間了,定時器替代了 cron 功能,這一特性值得看看。本文將向你介紹在系統啟動後如何使用 systemd 中的定時器來運行任務,並在此後重複運行。這不是對 systemd 的全面討論,只是對此特性的一個介紹。
快速回顧:cron、anacron 與 systemd
cron 可以以幾分鐘到幾個月或更長時間的粒度調度運行一個任務。設置起來相對簡單,它只需要一個配置文件。雖然配置過程有些深奧,但一般用戶也可以使用。
然而,如果你的系統在需要執行的時間沒有運行,那麼 cron 會失敗。
anacron 克服了「系統沒有運行」的問題。它確保任務將在你的系統再次啟動時執行。雖然它旨在給管理員使用,但有些系統允許普通用戶訪問 anacron。
但是,anacron 的執行頻率不能低於每天一次。
cron 和 anacron 都存在執行上下文一致性的問題。必須注意任務運行時有效的環境與測試時使用的環境完全相同。必須提供相同的 shell、環境變數和路徑。這意味著測試和調試有時會很困難。
systemd 定時器提供了 cron 和 anacron 二者的優點,允許調度到分鐘粒度。確保在系統再次運行時執行任務,即使在預期的執行時間內系統處於關閉狀態。它對所有用戶都可用。你可以在它將要運行的環境中測試和調試執行。
但是,它的配置更加複雜,至少需要兩個配置文件。
如果你的 cron 和 anacron 配置可以很好地為你服務,那麼可能沒有理由改變。但是 systemd 至少值得研究,因為它可以簡化任何當前的 cron/anacron 工作方式。
配置
systemd 定時器執行功能至少需要兩個文件。這兩個是「 定時器單元 」和「 服務單元 」。(其執行的)「動作」不僅僅是簡單的命令,你還需要一個「作業」文件或腳本來執行必要的功能。
定時器單元文件定義調度表,而服務單元文件定義執行的任務。有關的更多詳細信息請參考 man systemd.timer
中提供的 .timer 單元。服務單元的詳細信息可在 man systemd.service
中找到。
單元文件存放在幾個位置(在手冊頁中有列出)。然而,對於普通用戶來說,最容易找到的位置可能是 ~/.config/systemd/user
。請注意,這裡的 user
是字元串 user
。
示例
此示例是一個創建用戶調度作業而不是(以 root 用戶身份運行的)系統調度作業的簡單示例。它將消息、日期和時間列印到文件中。
1、首先創建一個執行任務的 shell 腳本。在你的本地 bin
目錄中創建它,例如在 ~/bin/schedule-test.sh
中。
創建文件:
touch ~/bin/schedule-test.sh
然後將以下內容添加到你剛剛創建的文件中:
#!/bin/sh
echo "This is only a test: $(date)" >> "$HOME/schedule-test-output.txt"
記住賦予你的 shell 腳本執行許可權。
2、創建 .service 單元調用上面的腳本。在以下位置創建目錄與文件:~/.config/systemd/user/schedule-test.service
:
[Unit]
Description=A job to test the systemd scheduler
[Service]
Type=simple
ExecStart=/home/<user>/bin/schedule-test.sh
[Install]
WantedBy=default.target
請注意 <user>
應該是你的家目錄地址,但是單元文件路徑名中的 user
實際上是字元串 user
。
ExecStart
應該提供一個沒有變數的絕對地址。例外情況是,對於用戶單元文件,你可以用 %h
替換 $HOME
。換句話說,你可以使用:
ExecStart=%h/bin/schedule-test.sh
這僅用於用戶單元文件,而不適用於系統服務,因為在系統環境中運行時 %h
總是返回 /root
。其他特殊符號可在 man systemd.unit
的 SPECIFIERS
中找到。因為它超出了本文的範圍,所以這就是我們目前需要了解的關於特殊符號的全部內容。
3、創建一個 .timer 單元文件,該文件實際上調度你創建的 .service 單元文件。在 .service 單元文件相同位置創建它:~/.config/systemd/user/schedule-test.timer
。請注意,文件名僅在擴展名上有所不同,例如一個是 .service
,一個是 .timer
。
[Unit]
Description=Schedule a message every 1 minute
RefuseManualStart=no # Allow manual starts
RefuseManualStop=no # Allow manual stops
[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 minute thereafter
OnUnitActiveSec=60
#File describing job to execute
Unit=schedule-test.service
[Install]
WantedBy=timers.target
請注意,這個 .timer 單元文件使用了 OnUnitActiveSec
來指定調度表。OnCalendar
選項更加靈活。例如:
# run on the minute of every minute every hour of every day
OnCalendar=*-*-* *:*:00
# run on the hour of every hour of every day
OnCalendar=*-*-* *:00:00
# run every day
OnCalendar=*-*-* 00:00:00
# run 11:12:13 of the first or fifth day of any month of the year
# 2012, but only if that day is a Thursday or Friday
OnCalendar=Thu,Fri 2012-*-1,5 11:12:13
有關 OnCalendar
的更多信息參見 這裡。
4、所有的部件都已就位,但你應該進行測試,以確保一切正常。首先,啟用該用戶服務:
$ systemctl --user enable schedule-test.service
這將導致類似如下的輸出:
Created symlink /home/<user>/.config/systemd/user/default.target.wants/schedule-test.service → /home/<user>/.config/systemd/user/schedule-test.service.
現在執行測試工作:
$ systemctl --user start schedule-test.service
檢查你的輸出文件($HOME/schedule-test-output.txt
),確保你的腳本運行正常。應該只有一個條目,因為我們還沒有啟動定時器。必要時進行調試。如果你需要更改 .service 單元文件,而不是更改它調用的 shell 腳本,請不要忘記再次啟用該服務。
5、一旦作業正常運行,通過為服務啟用、啟動用戶定時器來實時調度作業:
$ systemctl --user enable schedule-test.timer
$ systemctl --user start schedule-test.timer
請注意,你已經在上面的步驟 4 中啟動、啟用了服務,因此只需要為它啟用、啟動定時器。
enable
命令會產生如下輸出:
Created symlink /home/<user>/.config/systemd/user/timers.target.wants/schedule-test.timer → /home/<user>/.config/systemd/user/schedule-test.timer.
start
命令將只是返回命令行界面提示符。
其他操作
你可以檢查和監控服務。如果你從系統服務收到錯誤,下面的第一個命令特別有用:
$ systemctl --user status schedule-test
$ systemctl --user list-unit-files
手動停止服務:
$ systemctl --user stop schedule-test.service
永久停止並禁用定時器和服務,重新載入守護程序配置並重置任何失敗通知:
$ systemctl --user stop schedule-test.timer
$ systemctl --user disable schedule-test.timer
$ systemctl --user stop schedule-test.service
$ systemctl --user disable schedule-test.service
$ systemctl --user daemon-reload
$ systemctl --user reset-failed
總結
本文以 systemd 定時器為出發點,但是 systemd 的內容遠不止於此。這篇文章應該為你提供一個基礎。你可以從 Fedora Magazine systemd 系列 開始探索更多。
參考
更多閱讀:
man systemd.timer
man systemd.service
- Use systemd timers instead of cronjobs
- Understanding and administering systemd
- https://opensource.com/ 內有 systemd 速查表
via: https://fedoramagazine.org/systemd-timers-for-scheduling-tasks/
作者:Richard England 選題:lujun9972 譯者:dcoliversun 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive