Tengo un archivo llamado botstart.service
con /etc/systemd/system
este contenido:
[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
Lo comencé systemctl enable botstart
y decía que estaba habilitado. Reinicié mi VPS, pero el script no se ejecutó. Lo hice systemctl status botstart
y me mostró esto:
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)
Si ejecuto el script manualmente, funciona, pero de alguna manera no como un servicio, pero el servicio se ejecuta y el script se ejecuta (eso es lo que me dice el estado del servicio). ¿Alguien sabe por qué? Este es el código del script:
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"
Respuesta1
En su [Service]
sección, no definió explícitamente un archivo Type=
. Esto significa que por defecto será Type=simple
.
La página de manual dice:
Si se configura en simple, el administrador de servicios considerará que la unidad se inició inmediatamente después de que se haya bifurcado el proceso de servicio principal. Se espera que el proceso configurado con ExecStart= sea el proceso principal del servicio....
En resumen, su guión es el proceso principal. Inicia una serie de procesos y luego sale. systemd
ve que su proceso principal sale y luego procede a limpiar los procesos secundarios que ya no tienen un padre.
En lugar de eso quieres Type=forking
.
Si se configura en bifurcación, se espera que el proceso configurado con ExecStart= llame a fork() como parte de su inicio. Se espera que el proceso principal finalice cuando se complete el inicio y se configuren todos los canales de comunicación. El hijo continúa ejecutándose como el proceso de servicio principal y el administrador de servicios considerará que la unidad se inició cuando el proceso padre salga. Este es el comportamiento de los servicios tradicionales de UNIX. Si se utiliza esta configuración, se recomienda usar también la opción PIDFile=, para que systemd pueda identificar de manera confiable el proceso principal del servicio.
En este caso, se permitirá que sus procesos secundarios sigan vivos, incluso después de que finalice su script. Si agrega Type=forking
, las cosas deberían funcionar mejor para usted.
Tenga en cuenta que existen otros problemas con su diseño. Si el único cambio que realiza es Type=forking
, todavía tiene algunos problemas:
- Si uno de los procesos finaliza, systemd puede decidir o no cuál es el MainPID y considerar todo su servicio
inactive (dead)
. Escribir en aPIDFile=
puede ayudar con esto, pero sospecho que no pretende que ninguno de estos procesos sea el MainPID. - Si un proceso falla,
systemd
no se puede informar un estado fallido. No está claro qué debería pasar con los otros procesos.
Recomendación 1: dividir cada proceso en su propio servicio. Entonces Type=simple
funcionará. De esta manera, si un servicio falla, puedes detectarlo y operarlo de manera confiable sin afectar a los otros bots.
Recomendación 2: Agregar Restart=on-failure
. Esto permitirá que un servicio fallido se reinicie automáticamente (no se requiere intervención humana).
Recomendación 3: No llames bash
a quién screen
llama python3
. Simplemente llame a Python directamente. screen
es una solución alternativa que no es necesaria en un systemd
entorno.
Recomendación 4: Para implementar eso sleep 3
, puedes usar unExecStartPre=
Siguiendo estas recomendaciones, nyoko.service
quedaría así:
[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
Recomendación 5: sleep
no es demasiado fiable. En un buen día, pierde 3 segundos. En un mal día, no es suficiente y tu servicio fallará. Considere agregar After=lavalink.service
a su [Unit]
sección para asegurarse lavalink.service
de que se inicie antes que algo que dependa de ello. Si lavalink
tiene algún tipo de señal que muestra que se inició (se crea el archivo o se abre el socket), entonces puede activarlo.