はいはいはいはい、皆さんこんにちは、○○です。
ええ、自粛期間中はYoutubeが捗りますね、いつも面白い動画をありがとうございます。
systemd
を用いてデーモンを特定の時間帯だけ起動させる方法についてです。
意外と需要ありそうなのですが関連する記事が見当たらなかったので備忘録的に試行錯誤を記しておこうと思います。
やりたいこと
8時から23時の間だけデーモン(以下ダエモンさんことMr.daemon)を起動しておきたい。
その他の時間は消費電力削減のために停止しておきたい。
ちなみに、操作したいデーモンは自作のもので、起動中にffmpeg
でHLSを用いて音声をストリーミング配信し続けるというものです。
余談ですがサービスとデーモンの何が違うのか調べたら、どちらも常駐プログラムで、サービスはWindows系で使われデーモンはUnix系で使われるそうです。
まず思いついた方法
後ほど問題点を記しますがとりあえず。
起動編
systemd
を用いたダエモンさんの起動方法は主に二つ挙げられると思います。
-
自動起動
systemctl enable {Mr.daemon}
-
手動起動
systemctl start {Mr.daemon}
ですが、これらの方法では時間を指定することはできません。
自動起動ではいつ何時も問答無用で起動してしまいますし、手動起動は言わずもがなです。
そこで時間を指定するためには以下の方法を使えるかと思います。
-
タイマー
{Mr.daemon}.timer
-
cron
0 8 * * * systemctl start {Mr.daemon}
systemd
のタイマー
systemd
のタイマー機能を利用して特定の時間にダエモンさんを起動できます。
[Unit]
# 任意の説明
Description=Run {Mr.daemon}.service
[Timer]
# 起動したい時刻
OnCalendar=*-*-* 8:00:00 #year-month-date hour:minute:second
# OnCalenderで指定した時刻にOSが寝ていた場合、次回起動時にデーモンを起動
Persistent=true
[Install]
WantedBy=timers.target
このようにユニットファイルを記したらsudo systemctl enable {Mr.daemon}.timer
でタイマーを有効にします。
管理者権限cron
管理者権限のcron
でも時間を指定してsystemctl start
を走らせることで同様のことができます。
sudo crontab -e
- 右を追記
0 8 * * * systemctl start {Mr.daemon}
停止編
systemdのタイマーでは起動することはできても停止することはできないそうです。
ですので停止するためにはいずれにせよcron
を使います。
管理者権限のcron
に以下のように追記すればよいです。
0 23 * * * systemctl stop {Mr.daemon}
上記方法の問題点
さて、上の方法で実装したところ幾つか不都合がありました。
それは8時から23時の間に再起動した後デーモンが起動しないという点です。
当然ですが始まりと終わりのトリガーしか設定していないので、例えばメンテナンス等で9時に再起動した場合は手動で起動しないと翌8時までダエモンさんは眠ったままです。
これでは特定の時間帯だけ稼働するデーモンとしては不十分です。
ではどうするか
デーモンの起動スクリプトをいじることにしました。
### 追記部分
NOW=`date +%H` #現在時刻の取得
if [ $NOW -ge 23 -o $NOW -lt 8 ]; then #現在時刻が23時~翌8時の間なら
systemctl stop {Mr.daemon} #デーモンを停止
exit 0 #正常終了
fi
###
function fork() {
#処理
}
fork > /dev/null 2>&1 </dev/null &
echo $! > /run/{Mr.daemon}.pid
追記部分で23時から翌8時の間にこのスクリプトが走ると処理から抜けるようにしてあります。
この状態でsudo systemctl enable {Mr.daemon}
として、常に自動起動するようにします。
8時から23時の間では自動起動しますが、23時から翌8時の間は自動起動がキャンセルされるのでダエモンさんは眠ったままです。
最初に試したsystemd
のタイマーとデーモンを停止するcron
と組み合わせれば特定の時間帯に起動しているダエモンさんの出来上がりです。
解説
当初if
の中はexit
だけでしたが、その状態だと起動が失敗したとエラーが吐かれてしまいました。
exit 0
として正常終了を返しても同じでした。
別に問題ないといえばそれまでなのですが気持ちが悪いのでsystemctl stop {Mr.daemon}
を記述したところ起動キャンセル扱いとなりエラーは出なくなりました。
cron
では?
試していませんがデーモン起動スクリプトをいじれなければ同様のことをcron
でも実現できるでしょう。
@reboot if [ $NOW -lt 23 -a $NOW -ge 8 ]; then systemctl start {Mr.daemon}; fi
このように管理者権限cron
に追記しておけば23時から8時の間にOSが起動された時ダエモンさんも起動します。
無駄に起動させないのでcron
のほうがスマートな気もしますがAfter
や依存関係などsystemd
関連の順番を調整するのが面倒だったのでsystemd
のほうで自動起動するようにしました。
最後に
どうも何れのやり方もスマートな感じがしないので良い方法をご存じの方がいらっしゃいましたらご教授ください。