systemd .timerについて調べた事を記事にしておく
Contents
systemd.timer
systemdの.timerファイルについて調べた事を記事として残しておく。
以前のsystemdによる自動起動の記事で.serviceファイルについて書いたが.timerファイルはcronの様なタイマー起動の制御が出来るのだとは思ったのだがその時は詳しくは調べなかった。
最近のLinuxではsystemdによるプロセスの制御を推奨している様なのでこの機会に.timerについて調べてみた。
環境
試した環境は以下の通り。
ラズパイのOSのRaspbianで試したがRaspbianはUbuntuがベースなのでDebian系のLinuxであれば(恐らくそれ以外でも)ほぼ同じ様な指定で動作すると思う。
本体 | Raspberry Pi 3 B+ |
OS | Raspbian Version:June 2019 |
動作例
ファイルの保存場所
XXX.serviceファイルとXXXの部分が同じXXX.timerファイルを作成する。
.serviceファイルには実行するプロセスの情報(詳細は以前の記事を参照).timerファイルにはタイマー情報を記述して/etc/systemd/system/配下に保存する。
尚、ファイルの保存場所は/usr/lib/systemd/system/(システムデフォルト)に保存する事も可能だが同名のファイルがある場合は/etc/systemd/system/が優先される。
.serviceファイル
テストとして以下のdatetest.serviceファイルを用意した。
[Unit]
Description = RaspberryPi Test process
After=network-online.target
[Service]
ExecStart=/home/pi/datetest.sh
User=pi
Group=pi
[Install]
WantedBy=multi-user.target
やっていることは/home/pi/datetest.shをユーザ、グループともにpi(ラズパイのデフォルトユーザ)で起動している。
ユーザ(pi)を指定したのは下記のshファイルで実行結果をファイルに保存しているのだが未指定だとroot権限でファイルを書き込んでしまうのでユーザ=piでファイルを作成するようにした。
shファイル
ホームディレクトリに以下のdatetest.shファイルを用意した。
#!/bin/bash
/bin/date >> /home/pi/datetest.log
dateコマンドを実行してホームディレクトリ上のファイルに結果をリダイレクトしている。
尚、リダイレクト先のファイル名はフルパスで指定している。
フルパスで指定するか事前にカレントディレクトリをユーザpiで書込み可能なディレクトリに移動をしておく必要があるので注意。
.timerファイル
上記のコマンドを1分間隔で実行するようにdatetest.timerファイルを以下の内容で作成する。
[Unit]
Description = RaspberryPi Test timer
[Timer]
OnUnitActiveSec=1min
Unit=datetest.service
[Install]
WantedBy=multi-user.target
OnUnitActiveSecは対象のユニットが最後に起動されてからの間隔を指定する。
その他のTimerセクションの指定方法については後述する。
スタートする
以下のコマンドで.service及び.timerを開始する。
尚、スタートオプションは”今”開始するだけでOSを再起動したら停止してしまう。
まずはスタートしてみてエラーが出ないことを確認する。
sudo systemctl start datetest.service
sudo systemctl start datetest.timer
尚、ファイルを修正した場合は以下のコマンドでリロードする。
sudo systemctl daemon-reload
自動起動
1分毎にシェルが起動されることを確認したらラズパイのOS起動時に自動的に実行されるように以下のコマンドを実行する。
sudo systemctl enable datetest.service
sudo systemctl enable datetest.timer
上記によりOS起動時に自動的にプロセスが実行されるようになる。
ステータスの確認
startやenableした後は以下のコマンドでステータスを確認する。
sudo systemctl status datetest.service
sudo systemctl status datetest.timer
エラーログ
エラーの場合は以下のログを確認する。
- /var/log/syslog
- /var/log/message
自分の場合は「権限が無い」か「スペルを間違えた」のどちらかの理由がほとんどだった。
実行結果
正常に実行された時の出力結果は以下の通り。
1分毎の指定(1min)を指定したので大体1分間隔で日付時刻が記録されているがあまり正確ではない。
恐らくだがOnUnitActiveSecは対象のユニットが最後に起動されてからの間隔なので起動に時間がかかるとその分ずれてくるのだと思われる。
また後述するがデフォルトだとタイマーの精度が1分単位なので、元々それ程正確では無い。
Timerセクション
Timerセクションのその他の指定方法について記述しておく。
OnActiveSec
タイマーがアクティブになった瞬間を基準にする。
OnBootSec
マシンが起動された時を基準にする。
システムサービスマネージャーの場合は下記のOnStartupSecとほぼ同じ意味になる。
OnBootSec=3min
OnUnitActiveSec=1min
上記の例は起動から3分後に開始して以後、1分毎の指定となる。
OnStartupSec
サービスマネージャが最初に開始された時を基準にする。
システムサービスマネージャーの場合はOS起動と同時に開始されるので上記のOnBootSecとほぼ同じタイミングになる。
しかしユーザサービスマネージャーは最初のログイン時のみに実行されるのでsystemctlコマンドで特定のユーザを指定した場合はブート時とは異なるタイミングになるはず。
“はず”としたのはサービス、タイマーファイルを/etc/systemd/user/ や ~/.config/systemd/user/に保存して、
systemctl --user start datetest.service
で起動すればユーザサービスマネージャーの指定が出来そうなのだが何故かうまく行かなかった(ファイルが見つからないのエラーになってしまう)。
Raspbianのバージョンの問題なのかその他の理由なのか原因不明なので理由が分かったら追記したいと思う。
OnUnitActiveSec
(タイマーがアクディブにしてる)ユニットが最後にアクティブにされた時を基準にする。
OnUnitInactiveSec
(タイマーがアクディブにしてる)ユニットが最後に”非アクティブ”にされた時を基準にする。
時間の単位
指定可能な時間の単位は以下の通り。
マイクロ秒 | usec、us、µs |
ミリ秒 | msec、ms |
秒 | seconds、second、sec、s |
分 | minutes、minute、min、m |
時 | hours、hour、hr、h |
日 | days、day、d |
週 | weeks、week、w |
月 | months、month、M |
年 | years、year、y |
OnCalendar
上記までの指定とは異なりカレンダー形式でタイマーを指定する時のオプション。
曜日 年-月-日 時-分-秒の形式で指定する。
- “,”(カンマ):or条件
- “*”(アスタリスク):ワイルドカード(任意の値)
- “..”(コロン2つ):範囲指定
- “/”(スラッシュ):/(スラッシュ)以降で指定された値だけカウントアップする。例えば2020/2-01-01とすると2020年1月1日→2022年1月1日→2024年1月1日・・・となる
OnCalendar=Thu,Fri 2020-*-1,5 11:12:13
上記の指定例は2020年の任意の月の1日または5日が木曜日または金曜日の11時12分13秒となる。
AccuracySec
タイマーの精度を指定する。
消費電力を最適化して不要なCPUウェイクアップを抑制するために指定される。
デフォルトは1分となっており1us(1マイクロ秒)を指定すれば精度は高くなるが消費電力も増す。
RandomizedDelaySec
0から指定された値までの間の時間をランダムで遅延する。
このオプションを指定する意味は複数のタイマーが指定された際に同時に実行されてリソースが輻輳して処理時間が遅くなることを防ぐ目的との事。
OnClockChange、OnTimezoneChange
TrueまたはFalse(デフォルト)が指定できる。
OnClockChangeをTrueにするとCLOCK_REALTIMEがCLOCK_MONOTONICに変わった時にイベントが実行される。
- CLOCK_REALTIME:システム時刻(タイムサーバーで時刻を補正したりすると時間が戻ることがある)
- CLOCK_MONOTONIC:ある時点(通常はシステム起動時点)からの経過時間。不可逆で減ることは無い
OnTimezoneChange=Trueにするとタイムゾーンを変更した時にイベントが発生する。
Unit
タイマーから実行するユニットファイル名を指定する。
Persistent
TrueまたはFalse(デフォルト)が指定できる。
Persistent=Trueを指定するとサービスユニットが最後に実行された時刻が保存されてタイマーが非アクディブで実行されなかったイベントがアクティブになった瞬間に実行される。
例えば電源をオフにしていて実行されなかったイベントが電源オンと同時に実行される。
尚、このオプションはOnCalendarで指定されたタイマーでのみ指定が可能なので注意。
WakeSystem
TrueまたはFalse(デフォルト)が指定できる。
Trueの場合、システムの一時停止から再開できるようなのだが正直、良く分からなかった。
スリープモードがあるOSの再開などに使用するのだろうか。
RemainAfterElapse
True(デフォルト)またはFalseが指定できる。
正直良く分からなかった。
Falseにするとタイマーが複数回起動された時にサービスが複数回起動できるようになるらしい。。。
アクティブなタイマーの確認
以下のコマンドでアクティブなタイマーを確認できる。
systemctl -t timer
次回の実行予定
以下のコマンドでタイマーの前回や次回の実行予定の一覧が表示される。
systemctl list-timers
最後に
以上で今回の記事を終了とする。
この記事が何処かで誰かの役に立つことを願っている。
尚、当記事中の商品へのリンクはAmazonアソシエイトへのリンクが含まれています。Amazonのアソシエイトとして、当メディアは適格販売により収入を得ていますのでご了承ください。
最近のコメント