Подтвердить что ты не робот

Как реализовать простой кроссплатформенный демон Python?

Я хочу, чтобы моя программа Python запускалась в фоновом режиме в качестве демона в Windows или Unix. Я вижу, что пакет python-daemon предназначен только для Unix; есть ли альтернатива для кросс-платформы? Если возможно, я хотел бы сохранить код как можно проще.

4b9b3361

Ответ 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, хотя