次のような内容のファイルがありますbotstart.service
:/etc/systemd/system
[Unit]
Description=Start all discord bots (AntiSpam, AutoChat, Nyoko, Helper) and the lavalink server.
[Service]
ExecStart=/bin/bash /home/scripts/start.sh
[Install]
WantedBy=multi-user.target
起動するsystemctl enable botstart
と、有効になっていると表示されました。VPS を再起動しましたが、スクリプトは実行されませんでした。再起動するsystemctl status botstart
と、次のように表示されました。
root@Hetzner-01:~# systemctl status botstart
● botstart.service - Start all discord bots (AntiSpam, AutoChat, Nyoko, Helper)
Loaded: loaded (/etc/systemd/system/botstart.service; enabled; vendor preset:
Active: inactive (dead) since Wed 2021-10-27 01:37:10 CEST; 50s ago
Process: 481 ExecStart=/bin/bash /home/scripts/start.sh (code=eited, status=0
Main PID: 481 (code=existed, status=0/SUCCESS)
Oct 27 01:37:07 Hetzner-01 systemd[1]: STarted Start all discord bots (antiSpam,
Oct 27 01:37:10 Hetzner-01 bash[481]: Started all bots
Oct 27 01:37:10 Hetzner-01 systemd[1]: botstart.service: Succeeded.
lines 1-9/9 (END)...skipping...
● botstart.service - Start all discord bots (AntiSpam, AutoChat, Nyoko, Helper) and the lavalink server.
Loaded: loaded (/etc/systemd/system/botstart.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2021-10-27 01:37:10 CEST; 50s ago
Process: 481 ExecStart=/bin/bash /home/scripts/start.sh (code=eited, status=0/SUCCESS)
Main PID: 481 (code=existed, status=0/SUCCESS)
スクリプトを手動で実行すると、動作しますが、どういうわけかサービスとしては動作せず、サービスが実行され、スクリプトが実行されます (サービス ステータスが示しているのはこれです)。理由を知っている人はいますか? これはスクリプト コードです。
screen -dmS antispam bash -c "cd /home/AntiSpam; python3.8 main.py"
screen -dmS autochat bash -c "cd /home/AutoChat; python3.8 main.py"
screen -dmS helper bash -c "cd /home/Helper; python3.8 main.py"
screen -dmS lavalink bash -c "cd /home/Lavalink; python3.8 main.py"
sleep 3
screen -dmS nyoko bash -c "cd /home/Nyoko; python3.8 main.py"
echo "Started all bots"
答え1
セクションでは[Service]
、 を明示的に定義していませんType=
。つまり、デフォルトで になりますType=simple
。
man ページには次のように書かれています:
simple に設定すると、サービス マネージャーは、メイン サービス プロセスがフォークされた直後にユニットが開始されたと見なします。ExecStart= で構成されたプロセスは、サービスのメイン プロセスであることが想定されます。
つまり、スクリプトはメイン プロセスです。一連のプロセスを開始し、終了します。 systemd
メイン プロセスが終了したことを確認してから、親がなくなった子プロセスのクリーンアップに進みます。
代わりに、 を希望しますType=forking
。
forking に設定すると、ExecStart= で設定されたプロセスは、起動時に fork() を呼び出すことが想定されます。親プロセスは、起動が完了し、すべての通信チャネルがセットアップされると終了することが想定されます。子プロセスはメインのサービス プロセスとして実行され続け、サービス マネージャーは、親プロセスが終了したときにユニットが起動したと見なします。これは、従来の UNIX サービスの動作です。この設定を使用する場合は、systemd がサービスのメイン プロセスを確実に識別できるように、PIDFile= オプションも使用することをお勧めします。
この場合、スクリプトが終了した後でも、子プロセスは存続できます。 を追加するとType=forking
、動作が改善されるはずです。
デザインには他にもいくつか問題があることに注意してください。 のみ変更を加えた場合Type=forking
、まだいくつかの問題が残っています。
- プロセスの 1 つが終了すると、systemd はそれを MainPID と決定して、サービス全体を検討する場合があります
inactive (dead)
。 に書き込むと、PIDFile=
この問題が解決する可能性がありますが、これらのプロセスのいずれかを MainPID にすることは意図していないと思われます。 - プロセスが失敗した場合、
systemd
失敗状態が報告されない可能性があります。他のプロセスに何が起こるかは不明です。
推奨事項 1: 各プロセスを独自のサービスに分割します。これでType=simple
機能します。この方法では、1 つのサービスに障害が発生した場合、それを検出して、他のボットに影響を与えることなく確実に操作できます。
推奨事項 2: を追加しますRestart=on-failure
。これにより、障害が発生したサービスが自動的に再起動されるようになります (人間の介入は不要)。
bash
推奨事項 3: which がscreen
whichを呼び出す を呼び出さないでくださいpython3
。 python を直接呼び出します。 screen
は、環境では必要のない回避策ですsystemd
。
推奨事項4:それを実装するにはsleep 3
、ExecStartPre=
これらの推奨事項に従うと、nyoko.service
次のようになります。
[Unit]
Description=Nyoko discord bot
[Service]
WorkingDirectory=/home/Nyoko
ExecStartPre=/usr/bin/sleep 3
ExecStart=/usr/bin/python3 /home/Nyoko/main.py
Restart=on-failure
[Install]
WantedBy=multi-user.target
推奨事項 5: sleep
あまり信頼できません。調子が良い日には 3 秒を無駄にします。調子が悪い日には十分でなく、サービスが失敗します。セクションAfter=lavalink.service
に追加して、依存するものより先に開始されるよう[Unit]
にすることを検討してください。開始されたことを示す何らかのシグナル (ファイルの作成またはソケットのオープン) がある場合は、代わりにそれをトリガーできます。lavalink.service
lavalink