Я хочу, чтобы моя программа Python запускалась в фоновом режиме в качестве демона в Windows или Unix. Я вижу, что пакет python-daemon предназначен только для Unix; есть ли альтернатива для кросс-платформы? Если возможно, я хотел бы сохранить код как можно проще.
Как реализовать простой кроссплатформенный демон Python?
Ответ 1
Приходят на ум два варианта:
-
Перенесите свою программу в службу Windows. Вероятно, вы можете поделиться большей частью своего кода между двумя реализациями.
-
Использует ли ваша программа какие-либо функции демона? Если нет, вы перепишите его как простой сервер, который работает в фоновом режиме, управляет связью через сокеты и выполняет свои задачи. Вероятно, он потребляет больше системных ресурсов, чем демон, но это будет независимой от платформы.
Ответ 2
В Windows это называется "услугой", и вы можете реализовать ее довольно легко, например. с модулем win32serviceutil, частью pywin32. К сожалению, две "ментальные модели" - служба против демона - очень различны в деталях, хотя они и служат в аналогичных целях, и я не знаю ни одного фасада Python, который пытается объединить их в единую структуру.
Ответ 3
Этот вопрос 6 лет, но у меня была та же проблема, и существующие ответы не были достаточно кросс-платформенными для моего использования. Хотя службы Windows часто используются аналогично демонам Unix, в конце концов они существенно различаются и "дьявол в деталях". Короче говоря, я попытался найти что-то, что позволяет мне запускать тот же код приложения как в Unix, так и в Windows, выполняя ожидания для хорошо зарекомендовавшего себя Unix-демона (который лучше объяснить в другом месте) как можно лучше на обеих платформах:
- Закройте дескрипторы открытых файлов (как правило, все они, но некоторым приложениям может понадобиться защитить некоторые дескрипторы от закрытия)
- Измените рабочий каталог для процесса на подходящее место, чтобы предотвратить ошибки "Directory Busy".
- Измените маску создания доступа к файлу (
os.umask
в мире Python) - Переместите приложение в фоновый режим и отделите его от инициирующего процесса.
- Полностью развод с терминалом, включая перенаправление
STDIN
,STDOUT
иSTDERR
в разные потоки (частоDEVNULL
) и предотвращение повторного захвата управляющего терминала - Обрабатывать сигналы, в частности,
SIGTERM
.
Основная проблема кросс-платформенной демонализации заключается в том, что Windows, как операционная система, действительно не поддерживает понятие демона: приложения, которые начинаются с терминала (или в любом другом интерактивном контексте, включая запуск из Explorer, и т.д.) будет продолжать работать с видимым окном, если контрольное приложение (в этом примере, Python) не включает графический интерфейс без окон. Кроме того, обработка сигналов Windows крайне неадекватна, и попытки отправить сигналы на независимый процесс Python (в отличие от подпроцесса, который не выдерживает закрытия терминала) почти всегда приведет к немедленному завершению этого процесса Python без каких-либо очистка (нет finally:
, no atexit
, no __del__
и т.д.).
Службы Windows (хотя и являются жизнеспособной альтернативой во многих случаях) были в основном из-за меня: они не являются кросс-платформенными, и они нуждаются в модификации кода. pythonw.exe
(a версия без окон Python, которая поставляется со всеми последними двоичными файлами Windows Python) ближе, но она по-прежнему не совсем делает разрез: в частности, это не удается улучшить ситуацию для обработки сигналов, и вы все еще не можете легко запустить приложение pythonw.exe
из терминала и взаимодействовать с ним во время запуска (например, чтобы доставить динамические аргументы запуска вашему script, скажем, пожалуй, паролю, путь к файлу и т.д.), до "демонализация".
В конце концов, я решил использовать subprocess.Popen
с ключевым словом creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
для создания независимого процесса без окон:
import subprocess
independent_process = subprocess.Popen(
'/path/to/pythonw.exe /path/to/file.py',
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP
)
Тем не менее, это все еще оставило меня с добавленной задачей запуска коммуникаций и обработки сигналов. Не вдаваясь в тонну деталей, для первой моей стратегии было:
-
pickle
важные части пространства имен запуска - Сохраните это в
tempfile
- Добавить путь к этому файлу в среде дочернего процесса перед запуском
- Извлечь и вернуть пространство имен из функции "демонанизация"
Для обработки сигналов мне пришлось немного поучиться. В рамках процесса "daemonized":
- Игнорировать сигналы в процессе демона, поскольку, как уже упоминалось, все они завершают процесс немедленно и без очистки
- Создайте новый поток для управления обработкой сигналов.
- Этот поток запускает дочерние процессы обработки сигналов и ждет их завершения.
- Внешние приложения отправляют сигналы процессу обработки дочерних сигналов, что приводит к его завершению и завершению.
- Затем эти процессы используют номер сигнала в качестве кода возврата
- Поток обработки сигналов считывает код возврата, а затем вызывает либо пользовательский обработчик сигналов, либо использует API-интерфейс cytpes для создания соответствующего исключения в основном потоке Python.
- Промыть и повторить для новых сигналов
Что все говорят, что для тех, кто сталкивается с этой проблемой в будущем, я развернул библиотеку под названием daemoniker, которая обертывает оба правильная демонстрация Unix и вышеупомянутая стратегия Windows в единый фасад. кросс-платформенный API выглядит следующим образом:
from daemoniker import Daemonizer
with Daemonizer() as (is_setup, daemonizer):
if is_setup:
# This code is run before daemonization.
do_things_here()
# We need to explicitly pass resources to the daemon; other variables
# may not be correct
is_parent, my_arg1, my_arg2 = daemonizer(
path_to_pid_file,
my_arg1,
my_arg2
)
if is_parent:
# Run code in the parent after daemonization
parent_only_code()
# We are now daemonized, and the parent just exited.
code_continues_here()
Ответ 4
В общем, понятие демона является специфичным для Unix, в частности ожидаемым поведением в отношении масок создания файлов, иерархии процессов и обработки сигналов.
Вы можете найти PEP 3143, в котором предложено продолжение python-daemon рассматривается для Python 3.2, и обсуждаются многие связанные демонационные модули и реализации.
Ответ 5
Причина, по которой это только unix, заключается в том, что демоны - это конкретная концепция Unix, то есть фоновый процесс, инициированный os и обычно выполняющийся как дочерний корневого PID.
Windows не имеет прямого эквивалента демона unix, самым близким, о котором я могу думать, является служба Windows.
Там есть программа под названием pythonservice.exe для Windows. Не уверен, поддерживает ли он все версии python, хотя