先日、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]定義を以下にします。

C.service
[Unit]
After = A.service
Requires = A.service

サービス(A)のsystemd.service

サービス(A)のsystemd.serviceの[Service]Typeをnotifyにします。
マニュアル

A.service
[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)を実施している時間が赤くなりました。

Screenshot from 2018-04-16 21-03-36.png

※サービス名は公開できないので隠しています。

各言語のsdnotifyはこちら

検証はしていませんが、go,pythonのsdnotifyです。

https://github.com/coreos/go-systemd/blob/master/daemon/sdnotify.go
https://github.com/bb4242/sdnotify

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.