pythonプログラムのDaemon化
RaspberryPiで常時プログラムを走らせたい
ということで、python プログラムのサービス化を行いたい。 バグで死んでも、ゾンビのように再び復活させるように。 以前、一度やったことはあるのですが、全く記憶にないのでメモりつつ。
仕組みとしては、プロセスIDを管理して、プロセスIDが取れなければ、再び実行…という仕組み?のようです。
こちらを参考にして進めました。。。。。 というかそのまま。Python3系に変更した以外は、↑サイトの通りで行けました。
今回作ったPythonソースは、Python3.X用。 標準の実行環境が、Python2.X系なのかサービススタート時にエラー。
- Python3系で実行するように変更
ソース1行目を以下のように変更
#!/usr/bin/env python ↓ #!/usr/bin/env python3
python3 がインストール済み、かつPATHが通ってる前提です。 ただの変更ですが、エディタの文字コードによって、改行とかが入るとエラーになるようです。 私は、ソースコードをWindowsのSpyder(エンコード UTF-8)で編集しましたが、改行コードが入って改行コードを消さないとエラーになりました。
あと、常識なのかもしれませんが、1行目必須。コメントを頭に書きたかったので5行目くらいに書いてましたがエラー。。。
無駄に時間を費やしました。
- Python内のメイン関数へ追記
実行ファイル「checkLog.py」に以下を追記
# --------------------------------------------- # デーモン化 # --------------------------------------------- def daemonize(): pid = os.fork() if pid > 0: pid_file = open('/var/run/checkLog.pid','w') pid_file.write(str(pid)+"\n") pid_file.close() sys.exit() if pid == 0: main_loop() # --------------------------------------------- # メイン関数 # --------------------------------------------- if __name__ == '__main__': if RUN_ENV == "Windows": main_loop() # RaspberryPiで実行するときは、デーモン化 else: while True: daemonize()
注意すべきは、pid_file の名称。 後のサービス登録時に使いますのでわかりやすい名称に。
私の場合、メインの動作確認は、WIndowsで行って、実環境はRaspberryPiだったので、Windows環境では、デーモン化プロセスに入らないように「RUN_ENV」で分岐作ってます。 実行環境を、PATH?とかから取れるのかもですが、調べておらず、手動です。(いいやり方あったら教えてください)
- サービスへの登録
定義ファイルを作成(私の場合、ディレクトリもなかったので作成から。。。) 以下コマンドで、ディレクトリ・ファイルを作成
mkdir /usr/lib/systemd/system/ cd /usr/lib/systemd/system/ vi /usr/lib/systemd/system/checkLog.service
checkLog.service ファイルの中身は以下、
[Unit] Description=check_log [Service] ExecStart=[実行するpythonファイル] Restart=always Type=forking PIDFile=[pid_file指定したパス] [Install] WantedBy=multi-user.target
ここのPIDFileが先ほどの、pid_fileのパスと一致させる。 ファイル作成後、サービスとして登録
systemctl daemon-reload systemctl status checkLog.service
設定ファイルの checkLog.service の内容を更新したら都度、リロードが必要。 サービス起動後、以下でエラーがないか確認。
systemctl start checkLog
最後に、RaspberryPi立ち上がりと同時に起動するように設定を変更
systemctl enable checkLog.service
RaspberryPiを再起動して、動作を確認