Служба 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). Запись в PIDFile=может помочь в этом, но я подозреваю, что вы не собираетесь, чтобы какой-либо из этих процессов был MainPID.
  • Если процесс дает сбой, systemdможет не сообщать о состоянии сбоя. Неясно, что должно произойти с другими процессами.

Рекомендация 1: разделите каждый процесс на отдельную службу. Тогда Type=simpleэто сработает. Таким образом, если одна служба выйдет из строя, вы сможете обнаружить это и надежно работать с ней, не влияя на других ботов.

Рекомендация 2: Добавить Restart=on-failure. Это позволит неисправной службе автоматически перезапуститься (вмешательство человека не требуется).

Рекомендация 3: Не вызывайте bashwhich calls screenwhich calls 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есть какой-то сигнал, показывающий, что он запущен (создан файл или открыт сокет), то вы можете вместо этого запустить его.

Связанный контент