先日、systemdを使っていて、
- 「あるサービス(A)のある処理(B)が正常終了してから、別のサービス(C)を起動させたい。」
- 「あるサービス(A)のある処理(B)が異常終了したら、別のサービス(C)は起動させたくない。」
という状況になりました。
systemd.serviceは、[Unit]のAfterで起動順序を定義できます。
ですが、それはただ、ExecStart
を実行する順序が定義されるものであるため、
ある処理(B)が特に時間のかかる処理だった場合は(C)の起動が(A)を追い越してしまいます。
そこで、(A)に対して、少し細工をすることにしました。
前提条件
Linux系OSのsystemdを使っていること。
私はubuntuで実施してますが他のOSでも同じように動くと思います。
サービス(C)のsystemd.service
サービス(C)のsystemd.serviceの[Unit]定義を以下にします。
[Unit]
After = A.service
Requires = A.service
サービス(A)のsystemd.service
サービス(A)のsystemd.serviceの[Service]Typeをnotifyにします。
マニュアル
[Service]
Type = notify
こうすることで、サービスAのプログラムコードと連携できるようになります。
コードから通知を受けたタイミングで、起動処理が正常終了する、という意味になります。
サービス(A)に、sdnotifyを埋め込む。
今回はcppで書かれたサービスだったので、ここを参考に、notifyの処理を埋め込みます。
埋め込む場所は、同期を取りたい処理が正常終了するタイミングです。
#include <systemd/sd-daemon.h>
main(){
//
// 処理(B)
//
sd_notify(0, "READY=1");
//
// main処理
//
}
イニシャライズ処理をplotしてみる。
systemd-analyze plot > foo.svg
点線部分がsystemdによるExecStart
から、Type=notify
されるまでの時間がplotされたものです。
処理(B)を実施している時間が赤くなりました。
※サービス名は公開できないので隠しています。
各言語のsdnotifyはこちら
検証はしていませんが、go,pythonのsdnotifyです。
https://github.com/coreos/go-systemd/blob/master/daemon/sdnotify.go
https://github.com/bb4242/sdnotify