Raspberry Pi[59] 自作プログラムのサービス化

システムサービスだけではなく、自分で作ったプログラムもサービスとして動かすことができます。なんのメリットがあるかというと、systemctl コマンドで止めたり、動かしたり自由であること、エラーログを含めてユーザーが気にしなくてもログに記録してくれる。また、何らかの影響でプロセスが死んでも自動で再起動かけてくれるなど、自分でやると結構大変なことが簡単にできる。今回は二つのプロセスを動かすプログラムをサービス化してみました。この二つは最初に起動したプロセスが共有メモリをファイルに書き出し、それを二番目のプログラムが読んでプロセス間通信をするため、若干起動を遅らせるなどの処理をしています。

まず、必要なのは、各プログラムをサービスに登録することと、二つの関連を各ファイルが必要です。

#/etc/systemd/system/xing_alart.service

[Unit]
Description=XING Alert
After=network.target
PartOf=xing_all.target

[Service]
WorkingDirectory=/home/pi/work/XING
ExecStart=/home/pi/work/XING/xing_alart -d 1 -c /home/pi/work/XING/config_iwate_obc.txt -ip 2 "192.168.1.2" "192.168.100.201"
Restart=always
RestartSec=3
StandardOutput=null
StandardError=journal

[Install]
WantedBy=multi-user.target

🔹 [Unit] セクション

このセクションは「サービスの関係性や起動条件」を定義する部分。

Description=XING Alert

  • このサービスの説明(任意)
  • systemctl statusjournalctl で表示される名前になるだけ

After=network.target

  • ネットワークが有効になってから起動することを保証
  • ip オプションでネットワークを使っているため、これは重要

PartOf=xing_all.target

  • xing_all.targetstop または restart したときに、このサービスも連動して止まる・再起動される
  • ただし、xing_alart を個別に止めても xing_all.target には影響しない(一方向の関連)

🔹 [Service] セクション

サービスの本体の動作内容と挙動制御を定義する。

WorkingDirectory=/home/pi/work/XING

  • カレントディレクトリをここに設定
  • shared_id.txt など、相対パスでファイルアクセスするなら必須

ExecStart=...

  • 実行するコマンド
  • ここに書かれたプログラムがこのサービスの本体になる

Restart=always

  • プログラムが終了した場合、どんな理由であれ再起動する

RestartSec=3

  • 再起動するまで 3秒待つ

StandardOutput=null

  • printf() などの出力を 無視して捨てる
  • journal にログがたくさん出るのを防ぐため

StandardError=journal

  • fprintf(stderr, ...) のようなエラー出力は journal に記録される
  • 異常時のログはしっかり残せるようにしてある

🔹 [Install] セクション

このセクションは **「このサービスをいつ起動するか」**を決めるもの。

WantedBy=multi-user.target

  • システムが通常のマルチユーザー状態(ログイン可能な状態)になったときに、自動で起動される
  • sudo systemctl enable xing_alart をしたとき、このターゲットに登録される

後から起動するプログラムはほとんど同じ

# /etc/systemd/system/esp32-com.service

[Unit]
Description=ESP32 COM
Requires=xing_alart.service
After=xing_alart.service
PartOf=xing_all.target
# BindsTo=xing_alart.service

[Service]
Type=simple
WorkingDirectory=/home/pi/work/XING
ExecStartPre=/bin/sleep 2
ExecStart=/home/pi/work/XING/esp32-com -d 1
Restart=always
RestartSec=3
StandardOutput=null
StandardError=journal

[Install]
WantedBy=multi-user.target

先ほどと異なるところだけ説明すると

[Unit] セクションの違い

Requires=xing_alart.service

  • このサービスを起動するには xing_alart が必要
  • つまり、esp32_comstart すると、自動的に xing_alartstart される

After=xing_alart.service

  • 起動の順序制御
  • xing_alart が起動してから esp32_com を起動する(共有メモリ作成を待つため)

🔹 [Service] セクションの違い

ExecStartPre=/bin/sleep 2

  • ExecStart を実行する前に2秒間待機
  • これは xing_alart が共有メモリを作成・初期化し終わる時間を稼ぐための処置
  • 地味だけど、安定起動のためにとても効果的

必要だった systemctl コマンドを一連の作業ごとに分けて整理しておく。


✅ 1. サービスファイルを編集・反映

bashコピーする編集するsudo systemctl daemon-reload

✅ 2. サービスを有効化(起動時に自動起動)

bashコピーする編集するsudo systemctl enable esp32_com.service
  • WantedBy=multi-user.target に基づいて起動時に有効化される

※一緒に使っていた サービスを一括有効化するなら:

bashコピーする編集するsudo systemctl enable xing_all.target

xing_all.targetはこんな感じ

# /etc/systemd/system/xing_all.target

[Unit]
Description=All XING Services
Requires=xing_alart.service esp32_com.service
After=network.target

4. サービスの状態確認

bashコピーする編集するsudo systemctl **.service
  • 実行中かどうか・最終ログの一部が見られる

✅ 5. ログの確認(詳細ログ)

bashコピーする編集するsudo journalctl -u **.service -n 50 --no-pager
  • printf()stderr の出力、失敗理由などを確認
  • -n 50 は「直近50行」を表示。もっと見たいなら -n 100 とかに変更可能

✅ (補足)一括制御(target 経由)

bashコピーする編集するsudo systemctl restart xing_all.target
sudo systemctl stop xing_all.target
  • すべての関連サービス(PartOf=xing_all.target を持つ)を一気に制御できる