RaspberryPi[64] systemdのType=notifyでサービス間の起動順を正確に制御する方法

経緯

Raspberry Piで複数のsystemdサービスを連携させるとき、「起動順が合わず共有メモリが読めない」というトラブルはよくあります。私の環境でも esp32-com が xing_alart より先に動き出してしまい、sleep を入れて時間稼ぎしていました。
しかしこの方法だと再起動のタイミング次第で再発します。今回はその根本を systemdのType=notify と sd_notify() を使って解決した方法を紹介します。

問題点

作成側(xing_alart)が初期化完了を systemd に通知する。

待ち側(esp32-com)はその通知を受けてから起動する。

これを実現するのが、systemdのType=notifyとlibsystemdのsd_notify("READY=1") です。

手順

ライブラリの導入

sudo apt-get update
sudo apt-get install -y libsystemd-dev pkg-config

コード変更(先に動く側 共有メモリを作成する側

共有メモリの初期化と shared_id.txt の書き出しが終わった直後に追加:

#include <systemd/sd-daemon.h>

sd_notify(0, "READY=1");          // 起動完了を通知
sd_notify(0, "STATUS=Running");   // 任意:状態表示用

ビルド

 -lsystemd を追加

systemd設定例

先に起動する側

[Unit]
Description=XING alert service
After=local-fs.target

[Service]
Type=notify
ExecStart=/home/pi/work/XING/xing_alart -d 1
Restart=always

[Install]
WantedBy=multi-user.target

あとに起動する側

[Unit]
Description=ESP32 communication service
Requires=xing_alart.service
After=xing_alart.service

[Service]
ExecStart=/home/pi/work/XING/esp32-com -d 1
Restart=always

[Install]
WantedBy=multi-user.target