Debian 服务在启动时无法正确启动文件

Debian 服务在启动时无法正确启动文件

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

相关内容