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
.
手冊頁說:
如果設定為 simple,服務管理員將認為該單元在主服務程序被分叉後立即啟動。預計ExecStart=配置的程序是服務的主程序....
簡而言之,你的腳本就是主行程。它啟動一堆進程,然後退出。 systemd
看到主進程退出,然後繼續清理不再有父進程的子進程。
相反,你想要Type=forking
。
如果設定為 forking,則預期使用 ExecStart= 配置的程序將呼叫 fork() 作為其啟動的一部分。當啟動完成並且所有通訊通道都建立後,父進程預計將退出。子進程繼續作為主服務進程運行,當父進程退出時,服務管理員會認為該單元已啟動。這是傳統 UNIX 服務的行為。如果使用此設置,建議同時使用 PIDFile= 選項,以便 systemd 能夠可靠地識別服務的主程序。
在這種情況下,即使腳本結束後,您的子進程也將被允許生存。如果您添加Type=forking
,事情應該對您來說會更好。
請注意,您的設計還存在一些其他問題。如果您所做的唯一更改是Type=forking
,那麼您仍然會遇到一些問題:
- 如果其中一個進程結束,systemd 可能會也可能不會決定這是 MainPID 並考慮您的整個服務
inactive (dead)
。寫入 aPIDFile=
可能對此有所幫助,但我懷疑您不打算讓這些進程中的任何一個成為 MainPID。 - 如果進程失敗,
systemd
可能不會報告失敗狀態。目前還不清楚其他進程會發生什麼事。
建議1:將每個進程拆分為自己的服務。然後Type=simple
就可以工作了。這樣,如果一項服務發生故障,您可以檢測到它並可靠地對其進行操作,而不會影響其他機器人。
建議 2:添加Restart=on-failure
.這將允許失敗的服務自動重新啟動(無需人工幹預)。
建議3:不要呼叫bash
哪個呼叫screen
哪個呼叫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
有某種訊號表示它已啟動(檔案已建立或套接字已開啟),那麼您可以觸發它。