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
有某种信号表明它已启动(文件已创建或套接字已打开),那么您可以触发它。