systemd/定时器 - Arch Linux 中文维基

跳至內容

# systemd/定时器

出自 Arch Linux 中文维基
< Systemd

翻譯狀態：

- 本文（或部分內容）譯自 Systemd/Timers，最近一次同步於 2022-03-25，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- systemd
- Systemd/用戶
- systemd FAQ
- cron

Timers 是以 `.timer` 為後綴名的 systemd 單元文件，用於控制 `.service` 文件或事件。Timers 可用來替換 cron（閱讀 #替代 cron）。Timers 內置了實時定時事件和單調定時事件的支持，並可以異步執行這些事件。

## 定時器單元

Timers 是以 `.timer` 為後綴的 systemd 單元文件。Timers 和其他單元配置文件是類似的，它通過相同的路徑加載，不同的是包含了 `[Timer]` 部分。 `[Timer]` 部分定義了何時以及如何激活定時事件。Timers 可以被定義成以下兩種類型：

- 實時定時器（亦稱「掛鐘定時器」）通過日曆事件激活（類似於 cronjobs）定時任務。使用 `OnCalendar=` 來定義實時定時器。
- 單調定時器即在一個時間點經過一段時間後激活定時任務。所有的單調計時器都遵循如下形式： `OnTypeSec=`。 `OnBootSec` 和 `OnActiveSec` 是常用的單調定時器。

要查閱完整的定時器選項，參見 systemd.timer(5)。關於日曆事件和時間段的定義參見 systemd.time(7)。

## 服務單元

每個 `.timer` 文件所在目錄都得有一個對應的 `.service` 文件（如 `foo.timer` 和 `foo.service`）。`.timer` 文件激活並控制 `.service` 文件。對應的 `.service` 文件中不需要包含 `[Install]` 部分，因為這由 timer 單元接管。必要時可以通過在定時器的 `[Timer]` 部分指定 `Unit=` 選項來控制一個與定時器不同名的服務單元。

## 管理

使用 timer 單元只需像其他單元一樣 enable 或 start 即可（別忘了添加 `.timer` 後綴）。要查看所有已啟用的定時器，運行：

    $ systemctl list-timers

    NEXT                          LEFT        LAST                          PASSED     UNIT                         ACTIVATES
    Thu 2014-07-10 19:37:03 CEST  11h left    Wed 2014-07-09 19:37:03 CEST  12h ago    systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
    Fri 2014-07-11 00:00:00 CEST  15h left    Thu 2014-07-10 00:00:13 CEST  8h ago     logrotate.timer              logrotate.service

注意：

- 列出所有定時器（包括非活動的），使用下列命令： `systemctl list-timers --all`。
- 一個由定時器啟動的服務的狀態，如果不是正好被觸發的話，通常是未激活的。
- 若一個定時器不再同步，它可能會刪除它在 `/var/lib/systemd/timers` 下的 `stamp-*` 文件。這些空文件只用於表示每個定時器上次運行的時間。刪除後，他們將在下次定時器運行時自動重建。

## 示例

通過定時器預定執行的服務文件一般無需任何修改。以下示例將預定執行 `foo.service`，因此它的定時器應該被命名為 `foo.timer`。

### 單調定時器

定義一個在系統啟動 15 分鐘後執行，且之後每周都執行一次的定時器：

    /etc/systemd/system/foo.timer

    [Unit]
    Description=Run foo weekly and on boot

    [Timer]
    OnBootSec=15min
    OnUnitActiveSec=1w

    [Install]
    WantedBy=timers.target

### 實時定時器

定義一個每周執行一次（具體來講，指周一凌晨零點）的定時器。如果上次未執行（比如說系統當時沒有開機，這個行為由 `Persistent=true` 定義）就立即執行服務。

    /etc/systemd/system/foo.timer

    [Unit]
    Description=Run foo weekly

    [Timer]
    OnCalendar=weekly
    Persistent=true

    [Install]
    WantedBy=timers.target

更精確的時間可以通過 `OnCalendar` 參數以下列方式指定：

    星期 年-月-日 時:分:秒

可以用星號來表示任意值，用逗號分列可能值。以 `..` 分隔的兩個值指兩個值間的連續序列。

這是在每個月的前四天晚上中午 12 點，但僅當這一天是周一或周二時運行的例子：

    OnCalendar=Mon,Tue *-*-01..04 12:00:00

在每個月的第一個星期六運行：

     OnCalendar=Sat *-*-1..7 18:00:00

如果不需要以星期幾來界定，比如說在每天四點運行，請去掉星期項：

     OnCalendar=*-*-* 4:00:00

在不同的時間運行一個服務可以以多次指定 `OnCalendar` 的方式表示。在下面的例子中，這個服務在周內的 22:30 和周末的 20:00 運行：

     OnCalendar=Mon..Fri 22:30
     OnCalendar=Sat,Sun 20:00

更多信息請參閱 systemd.time(7)。

提示：

- 可以用 systemd-analyze 工具檢測 `OnCalendar` 項是否填寫正確，並計算下一次這個條件成立的時間。比如說可以用 `systemd-analyze calendar weekly` 或 `systemd-analyze calendar "Mon,Tue *-*-01..04 12:00:00"`。
- libfaketime包 包提供的 `faketime` 命令在測試各種情況時非常有用。
- 特殊的事件表達式如 `daily` 和 `weekly` 表示 特定的啟動時間，因此任何共享該日曆事件的定時器將同時啟動。如果該定時器的服務會競爭系統資源，那麼共享該日曆事件的定時器可能會引起系統性能下降。使用 `[Timer]` 部分中的 `RandomizedDelaySec` 選項可以通過隨機推遲定時器啟動來避免這個問題。參見 systemd.timer(5)。
- 向 `[Timer]` 部分添加 `AccuracySec=1us` 選項可以避免原有默認的精確值 1 分鐘造成的誤差。參見 systemd.timer(5)。

## 瞬態 .timer 單元

可以使用 `systemd-run` 創建一個瞬態 `.timer` 單元。即可以在不創建服務文件的情況下設置定時運行某個命令。比如說下面的命令可以在 30 秒鐘後創建一個文件：

    # systemd-run --on-active=30 /bin/touch /tmp/foo

也可以建立指定一個已經存在但沒有定義 timer 的服務文件。比如說，下面的命令會在 12 小時 30 分鐘後啟動名為 `someunit.service` 的服務：

    # systemd-run --on-active="12h 30m" --unit someunit.service

更多信息和例子參見 systemd-run(1)。

## 替代 cron

儘管 cron 毋庸置疑是最有名的計劃任務管理器，systemd 定時器仍可以作為一個替代品。

### 優勢

使用定時器的最主要的優勢在於每個任務都有它自己的 systemd 服務。這樣做的好處包括：

- 任務可以簡單地獨立於他們的定時器啟動，簡化調試。
- 每個任務可配置運行於特定的環境中（參見 systemd.exec(5)）。
- 任務可以使用 cgroups 特性。
- 任務可以配置依賴於其他 systemd 單元。
- 任務會被記錄於 systemd 日誌，便於調試。

### 注意事項

有些可以用 cron 輕易做到的事情僅僅使用 timer 組件會比較難辦：

- 創建過程：相比於在 crontab 中只需添加一行任務，使用 systemd 配置計劃任務需要創建兩個文件並運行好幾次 `systemctl` 命令。
- 郵件：目前還沒有內置與 cron `MAILTO` 類似的任務失敗時發送郵件的功能。可以在每個服務文件中配置 `OnFailure=` 來實現同樣的功能。

另外， systemd用戶服務定時器默認只會在用戶登錄時進行。但是，lingering 允許在啟動，且用戶沒有活動登錄會話時激活。

- 隨機延時：目前沒還有內置與 cron 類似的 `RANDOM_DELAY` 功能來指定一個數字用於定時器延時執行。（參見 bug report）。 你不想同時執行的服務必須手動設置它們的定時器。

  注意：`AccuracySec` 選項對於隨機錯開定時器執行時間是 沒有 作用的，因為它"會在所有本地定時器單元間同步" (`systemd.timer(5)`)。換句話說， `AccuracySec` 會以相同的量改變所有定時器激活時間。例如，所有 `OnCalendar=daily` 的定時器單元，指定 `AccuracySec=15m` 將同時在 00:00 到 00:15 觸發相關的服務。

### 發送郵件

可以配置 systemd 在單元失敗時發送電子郵件。Cron 的 `MAILTO` 會在任務向標準輸出或標準錯誤輸出時發送郵件，許多任務只在發生錯誤時輸出。首先需要兩個文件：一個用來發送郵件的可執行文件和一個用於啟動這個可執行文件的 .service 文件。在本例中，可執行文件只是一個由提供 `smtp-forwarder` 的包中給出的調用 `sendmail` 的shell 腳本：

    /usr/local/bin/systemd-email

    #!/bin/sh

    /usr/bin/sendmail -t <<ERRMAIL
    To: $1
    From: systemd <root@$HOSTNAME>
    Subject: $2
    Content-Transfer-Encoding: 8bit
    Content-Type: text/plain; charset=UTF-8

    $(systemctl status --full "$2")
    ERRMAIL

不論你用什麼可執行文件，應該都會像這個腳本一樣接收至少兩個參數：目標郵箱地址和用來獲取狀態的單元文件名。我們創建的 .service 文件會傳遞這些參數：

    /etc/systemd/system/status_email_user@.service

    [Unit]
    Description=status email for %i to user

    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/systemd-email address %i
    User=nobody
    Group=systemd-journal

其中，`user` 是被通知的用戶名，`address` 是該用戶的郵件地址。儘管這個地址被硬編碼在代碼裡，但是報告的單元文件會在實例參數中指定，因此可以作為許多其他單元的郵件服務端。此時你可以 start `status_email_user@dbus.service` 服務來檢查你能否收信。

成功後，僅需編輯你需要發送失敗郵件的服務，向 `[Unit]` 部分添加 `OnFailure=status_email_user@%n.service`。`%n` 會向模板傳遞單元的名字。

注意：

- 如果你根據 sSMTP#Security 配置了 sSMTP 安全，`nobody` 用戶會沒有訪問 `/etc/ssmtp/ssmtp.conf` 文件的權限，`systemctl start status_email_user@dbus.service` 命令就會失敗。一個解決辦法是使用 `root` 作為 `status_email_user@.service` 單元的執行者。
- 如果你希望在你的郵件腳本中使用 `mail -s somelogs address`，`mail` 會以 fork 的形式啟動，systemd 會把在你的腳本退出時一併將這個進程結束掉。可以用 `mail -Ssendwait -s somelogs address` 來讓 mail 不以 fork 的形式啟動。

### 使用 crontab

有些注意事項中的部分可以通過安裝一些將傳統 crontab 項目翻譯成 timers 配置的包來完成，例如AUR 中的 systemd-crontab-generatorAUR[損壞的連結：package not found] 和 systemd-cronAUR 包。他們也可以提供缺失的 `MAILTO` 特性。

同樣，與 crontab 一樣，可以通過 `systemctl` 來獲取一個統一的計劃任務視圖。參見 #管理章節。

## 參見

- systemd.timer(5)
- Fedora Project wiki page systemd 的實時定時器
- Gentoo wiki section on systemd timer services
- systemd-cron-next — 一個從 crontab 和 anacrontab 文件生成 timers/services 文件的工具

  https://github.com/systemd-cron/systemd-cron-next || systemd-cron-nextAUR

- systemd-cron — 提供 systemd 單元運行 cron 腳本；使用 systemd-crontab-generator 轉換 crontabs

  https://github.com/systemd-cron/systemd-cron || systemd-cronAUR

- Systemd Timers for Scheduling Tasks

分類：​

- 系統管理
- 包含損壞的軟體包連結的頁面

systemd/定时器
新增話題