Systemd/定時器
定時器是 systemd 中名稱以 .timer 結尾的單元文件,用於控制 .service 文件或事件。定時器可以用作 cron 的替代方案。定時器內置對基於日曆的事件和普通時間事件的支持,並且可以異步運行。
配置
以下示例定時器每 5 分鐘運行一次 systemd 單元以調用 bash 腳本。
systemd.timers."hello-world" = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "5m";
OnUnitActiveSec = "5m";
# Alternatively, if you prefer to specify an exact timestamp
# like one does in cron, you can use the `OnCalendar` option
# to specify a calendar event expression.
# Run every Monday at 10:00 AM in the Asia/Kolkata timezone.
#OnCalendar = "Mon *-*-* 10:00:00 Asia/Kolkata";
Unit = "hello-world.service";
};
};
systemd.services."hello-world" = {
script = ''
set -eu
${pkgs.coreutils}/bin/echo "Hello World"
'';
serviceConfig = {
Type = "oneshot";
User = "root";
RemainAfterExit = true; # Prevents the service from automatically starting on rebuild. See https://discourse.nixos.org/t/how-to-prevent-custom-systemd-service-from-restarting-on-nixos-rebuild-switch/43431
};
};
Alternatively here, avoid quotes when calling for the binary and its command options:
${pkgs.foo}/bin/foo command-options
This will yield the same result as running
foo command-options
in your terminal.
Verifying your timestamp for systemd.time
If you do not understand the format that systemd.time expects, you can use the systemd-analyze's calendar sub-command to understand the next N times when the timer will get triggered. Following is an example:
$ systemd-analyze calendar --iterations=5 "10:00:00"
Original form: 10:00:00
Normalized form: *-*-* 10:00:00
Next elapse: Sat 2024-12-07 10:00:00 IST
(in UTC): Sat 2024-12-07 04:30:00 UTC
From now: 33min left
Iteration #2: Sun 2024-12-08 10:00:00 IST
(in UTC): Sun 2024-12-08 04:30:00 UTC
From now: 24h left
Iteration #3: Mon 2024-12-09 10:00:00 IST
(in UTC): Mon 2024-12-09 04:30:00 UTC
From now: 2 days left
Iteration #4: Tue 2024-12-10 10:00:00 IST
(in UTC): Tue 2024-12-10 04:30:00 UTC
From now: 3 days left
Iteration #5: Wed 2024-12-11 10:00:00 IST
(in UTC): Wed 2024-12-11 04:30:00 UTC
From now: 4 days left
Using the systemd.services.<name>.startAt shorthand
If you only want a service to execute at an interval and don't plan to configure the timer much more, you can use the systemd.services.<name>.startAt option. This will have the underlying systemd module in nixpkgs create the timer for you, and set its OnCalendar field. Note that the semantics for OnCalendar are different to OnUnitActiveSec.
This example shows the previous hello-world service configured with startAt, running every 5 minutes.
systemd.services."hello-world" = {
script = ''
set -eu
${pkgs.coreutils}/bin/echo "Hello World"
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
startAt = "*:0/5";
};
Running timer on a schedule
以下示例每天啟動一次(凌晨 12:00)。激活後,例如如果由於系統關閉錯過了上次啟動時間(同時設置選項 Persistent=true),,則會立即觸發服務。
...
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
};
更多示例可以在 Arch Wiki 和 systemd.timer 手冊頁中找到。
用法
列出活躍定時器及其當前狀態:
systemctl list-timers
為了測試目的,手動運行一次服務:
systemctl start hello-world