Вопрос или проблема
Я пытаюсь запустить проект, написанный на Python, на сервере. Я создал следующий файл службы:
[Unit]
Description=My bot service
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/python3.10 /home/path/to/bot.py
[Install]
WantedBy=multi-user.target
Но этот код не работает. Если я проверяю статус службы, он возвращает следующее:
● test.service - My bot service
Loaded: loaded (/etc/systemd/system/test.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Fri 2022-10-21 08:16:07 UTC; 15s ago
Process: 156695 ExecStart=/usr/bin/python3.10 /home/path/to/bot.>
Main PID: 156695 (code=exited, status=1/FAILURE)
Oct 21 08:16:07 instance-1 systemd[1]: test.service: Scheduled restart job, restart coun>
Oct 21 08:16:07 instance-1 systemd[1]: Stopped My bot service.
Oct 21 08:16:07 instance-1 systemd[1]: names.service: Start request repeated too quickly.
Oct 21 08:16:07 instance-1 systemd[1]: test.service: Failed with result 'exit-code'.
Oct 21 08:16:07 instance-1 systemd[1]: Failed to start My bot service.
Когда я запускаю бота напрямую (/usr/bin/python3.10 /home/path/to/bot.py
), он работает.
Когда я запускаю простой скрипт на Python как службу, он тоже работает.
Я просто не понимаю, что может быть причиной проблемы внутри проекта. Добавление параметра WorkingDirectory
в конфигурационный файл ничего не изменило
bot.py
возвращает 1
.
Вам нужно исследовать код, чтобы увидеть, при каких условиях он может завершиться с этим кодом.
Первое, что я бы сделал, это удалил Restart=always
. Вы можете видеть, что ваш скрипт неудачно завершился, затем перезапустился, затем перезапустился, затем перезапустился, затем перестал пытаться. Скорее всего, если он не сработает в первый раз, он не сработает и позже. Так что в этой строке мало необходимости, пока у вас все не заработает достаточно хорошо. Все, что она делает, это засоряет вывод и вызывает путаницу во время разработки. Без этой строки systemctl status
мог бы выдать ваши последние несколько строк stdout
.
Следующее, что я бы сделал, это запустил эту службу и проверил журнал:
$ sudo systemctl start test.service
$ journalctl -u test.service --since "5 minutes ago"
Это может дать подсказки о том, что происходит, через stdout или stderr. Особенно проверьте трассировки исключений.
Если в журнале нет никакого вывода, это может быть потому, что python
завершил работу до того, как мог сбросить свой буфер. Используйте опцию -u
в python
, чтобы обеспечить неблокированный вывод:
ExecStart=/usr/bin/python3.10 -u /home/path/to/bot.py
Наконец, если этот бот создает окно и имеет GUI, есть специальные шаги, которые нужно предпринять (запустить это на --user
bus или установить переменную окружения DISPLAY=
). Я могу дать больше информации, если вы ожидаете GUI. Это сверхраспространенная причина проблем “Я могу запустить это, но systemd не может”.
.
Ответ или решение
Для успешного решения проблемы с запуском Python проекта в качестве systemd службы следует тщательно проанализировать и тестировать каждый элемент, чтобы выявить причину сбоя. Рассмотрим основные шаги, которые помогут в данной ситуации.
Теория
1. Структура systemd службы:
Systemd файлы подразделяются на три основных секции:
[Unit]
: информация о сервисе, его зависимостях и порядке запуска.[Service]
: инструкция по запуску программы, как она будет реагировать на события и как будет перезапускаться.[Install]
: определяет, когда сервис должен быть активирован.
Ключевой параметр в вашем файле — это ExecStart
, который определяет команду запуска Python скрипта.
2. Проблема выхода с кодом 1:
Код возврата 1 обычно указывает на общую ошибку. Это может быть связано с логикой программы, отсутствием необходимых ресурсов или зависимостей.
3. Буферизация вывода:
Python по умолчанию буферизует вывод, что может привести к тому, что ошибки или информация не сразу видны. Это можно изменить, используя опцию -u
для небуферизированного вывода.
Пример
-
Проверка статуса и журнала службы:
Используйте команду для проверки статуса:
sudo systemctl status test.service
Журнал событий поможет понять, что происходит при запуске:
journalctl -u test.service --since "5 minutes ago"
-
Настройка файла сервиса с небуферизированным выводом:
Измените строку запуска в вашем файле сервисов:
ExecStart=/usr/bin/python3.10 -u /home/path/to/bot.py
-
Отладка Python кода:
Если скрипт использует дополнительные ресурсы (файлы, соединения с базами данных, API и др.), убедитесь, что все они доступны службе. Возможно, потребуется задать переменные окружения или изменить права доступа.
Применение
1. Удаление Restart=always
:
Временно уберите строку Restart=always
из вашего файла службы. Это позволит получить исчерпывающую информацию о первоначальном состоянии после сбоя, без попыток повторных перезапусков, которые усложняют отладку.
2. Проверка зависимостей и доступов:
Проверьте все зависимости скрипта. Возможно, необходимы специальные разрешения или доступ к ресурсам, таким как Connect к базе данных, доступ к файлам, API и т.д. Важно, чтобы служба имела необходимые разрешения.
3. Проверка путей и окружения:
Убедитесь, что все пути указаны корректно. Помните, что пути указываются относительно корневой папки, поскольку systemd запускается как системный процесс. Если скрипт зависит от виртуального окружения, убедитесь, что оно правильно активировано в контексте службы.
Для установки корректного окружения можно использовать Environment
в секции [Service]
в файле сервиса, например:
[Service]
Environment="PYTHONPATH=/path/to/dependencies"
4. Работа с GUI приложениями:
В случае, если ваш бот имеет графический интерфейс, systemd требуется дополнительных настроек. Наиболее частая причина — это необходимость использования DISPLAY=
переменной. Для этого её также можно задать в секции Environment
.
Воспользуйтесь предложенными методами и техниками для постепенного устранения неисправности. Важно действовать поэтапно: сначала отладить и убедиться, что код работает в изолированном запуске; затем внимательно настроить systemd сервис. Это поможет вам не только выявить проблему, но и устранить её.