お久しぶりです、よ〜んです。

UNIXやGNU/Linuxのジョブの定時実行といえばcronですが、Amazon Linux 2023 (AL2023)では定時実行をsystemd timerで行うことが推奨されているようです。

AL2023 で廃止 - Amazon Linux 2023

なぜsystemd timer が推されているのか

GNU/Linuxでは、サービス管理、起動順序、ログ、失敗時の扱いがsystemd に集約されています。

だったら、定期実行も同じ世界に載せたほうが運用しやすい、ということだと私は考えます。

デフォルトでログが記録される

cronはログを保存しません。

なので、ログを残す場合、以下のようなおまじないをしてあげる必要がありました。

* * * * * command >> /var/log/job.log 2>&1

コーディングエージェントが良くやるやつですね

ステートがある

もちろんcronでもログを残したり、終了したらDBに状態を格納したり、Discordなどに通知する仕組みを入れておくことで状態を持たせることは可能です。

一方、systemd timer(というかsystemd)では、↑のような一手間を加えずに状態を持ちます。

リトライがある

そして、systemd側で状態を持っているということは、リトライが可能になります。

cronでも実行するジョブ側に自前実装でリトライさせることは可能です。

systemd service (NOT systemd timer)なら、失敗時の扱いを記述し、リトライさせることが可能です。

Restart=on-failure
RestartSec=30s
OnFailure=

systemd timerの機能の一つであるPersistent を使うことで、例えば10時に実行するjobがあったときに、ジョブ実行を行なっている計算機がシャットダウンしていても、計算機起動後にジョブを実行してくれます。

実行時間に厳密である必要はないが、大体このぐらいの時間に実行してほしいといったパターンにめっちゃ便利だなと思いました。


上記のような点から、systemd timerではcronで自前実装・不便だったポイントが標準で揃っていることがわかりました。

cronからsystemd timerに移行するには

たとえば、こういう cron があったとします。

0 3 * * * /usr/local/bin/daily.sh

まずは何を実行するか.service に、いつ実行するか.timer に書いていきます。

service 側

# /etc/systemd/system/daily.service
[Unit]
Description=daily task
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
User=ec2-user
WorkingDirectory=/opt/daily
ExecStart=/usr/local/bin/daily.sh

ここに「ジョブの本体」を書きます。
必要なら EnvironmentFile=Restart=on-failureRestartSec=30s もここに足せます。

ExecStartPre などを使うことで、 他にも、TimeoutStopSecを使うことで、

timer 側

こちら完全に定時実行のための設定を記述していきます。

# /etc/systemd/system/daily.timer
[Unit]
Description=Run daily job every day

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now daily.timer

system確認系のコマンドも、cron よりかなり分かりやすいです。

# 実行予定を確認
systemctl list-timers
# ステータスの確認
systemctl status daily.timer
# ログの確認(これは .service)
journalctl -u daily.service

見通しがかなり良くなりそうな気がしてます。

まとめ

cron は全然使えますし、自宅サーバーとかやったらcron使うかなって感じです。

ただ、AL2023 では推奨されていますし、実際のところプロダクションを見据えたとき、運用の見通しはかなりよくなると思いました。

cronの思い出

cronの思い出といえば、私がちょっとシェルを書けるようになった後に知りましたね…

cronを知る前はwhileループで現在の時間を取得して…みたいな馬鹿げたことをしていました…

もちろんデーモンという概念も知らない時です。

効率よくするために、一つのプログラムに複数のジョブを定義して時間で分岐することとかやってたり…

大学の出席(evil)とか、車校の予約(超evil)とか、ほんとに、そのままの今で私の人生を支えてきてくれていたなぁなどと

ではでは

systemd(1) - Linux manual page

systemd.timer(5) — Linux manual page