Как вы создаете демона в Python?
Поиск в Google показывает фрагменты кода x2. Первый результат этого рецепта кода, который содержит много документации и объяснений, а также некоторые полезные обсуждения ниже.
Тем не менее, другой пример кода, хотя и не содержит так много документации, включает пример кода для передачи таких команд, как запуск, остановка и перезапуск. Он также создает PID файл, который может быть полезен для проверки, запущен ли демон и т.д.
Оба примера объясняют, как создать демон. Есть ли какие-то дополнительные вещи, которые необходимо учитывать? Один образец лучше другого, и почему?
Ответы
Ответ 1
Текущее решение
Эталонная реализация PEP 3143 (Стандартная библиотека процессов демона) теперь доступна как python-daemon.
Исторический ответ
Пример кода Sander Marechal превосходит исходный, который был первоначально опубликован в 2004 году. Однажды я добавил демонизатор для Pyro, но, вероятно, использовал бы код Sander, если бы мне пришлось это делать заново.
Ответ 2
Есть много интересных вещей, о которых нужно позаботиться, когда вы станете хорошим демоном:
-
предотвращение дампов ядра (многие демоны запускаются от имени root, а дампы ядра могут содержать конфиденциальную информацию)
-
правильно вести себя внутри chroot
тюрьмы
-
установить UID, GID, рабочий каталог, umask и другие параметры процесса соответственно для варианта использования
-
отказаться от повышенных suid
, sgid
привилегии
-
закройте все дескрипторы открытого файла, с исключениями в зависимости от варианта использования
-
вести себя корректно, если он запущен внутри уже отсоединенного контекста, такого как init
, inetd
и т.д.
-
настроить обработчики сигналов для разумного поведения демона, а также с определенными обработчиками, определяемыми сценарием использования
-
перенаправить стандартные потоки stdin
, stdout
, stderr
поскольку у процесса-демона больше нет управляющего терминала
-
обрабатывать PID файл как совместную консультативную блокировку, которая сама по себе представляет собой целую червь со множеством противоречивых, но обоснованных способов поведения
-
разрешить надлежащую очистку после завершения процесса
-
на самом деле стать процессом демона, не приводя к зомби
Некоторые из них являются стандартными, как описано в канонической литературе по Unix (Расширенное программирование в среде UNIX, покойный У. Ричард Стивенс, Аддисон-Уэсли, 1992). Другие, такие как перенаправление потоков и обработка файлов PID, являются обычным поведением, которого ожидают большинство пользователей-демонов, но они менее стандартизированы.
Все они описаны в спецификации PEP 3143 "Стандартная библиотека процессов демона". Реализация ссылок на python-daemon работает на Python 2.7 или более поздней версии и Python 3.2 или более поздней.
Ответ 3
Вот мой базовый демоверсия "Howdy World" Python, с которой я начинаю работать, когда я разрабатываю новое приложение-демон.
#!/usr/bin/python
import time
from daemon import runner
class App():
def __init__(self):
self.stdin_path = '/dev/null'
self.stdout_path = '/dev/tty'
self.stderr_path = '/dev/tty'
self.pidfile_path = '/tmp/foo.pid'
self.pidfile_timeout = 5
def run(self):
while True:
print("Howdy! Gig'em! Whoop!")
time.sleep(10)
app = App()
daemon_runner = runner.DaemonRunner(app)
daemon_runner.do_action()
Обратите внимание, что вам понадобится библиотека python-daemon
. Вы можете установить его:
pip install python-daemon
Затем просто запустите его с помощью ./howdy.py start
и остановите его с помощью ./howdy.py stop
.
Ответ 4
Обратите внимание на пакет python-daemon, который решает много проблем, стоящих за демонами из коробки.
Среди других функций он позволяет (из описания пакета Debian):
- Отключите процесс в своей группе процессов.
- Установить среду процесса, подходящую для работы внутри chroot.
- Отказаться от прав suid и sgid.
- Закройте все дескрипторы открытых файлов.
- Измените рабочий каталог, uid, gid и umask.
- Установите соответствующие обработчики сигналов.
- Откройте новые дескрипторы файлов для stdin, stdout и stderr.
- Управление указанным файлом блокировки PID.
- Зарегистрируйте функции очистки для обработки при выходе.
Ответ 5
Альтернатива - создайте нормальную, не-демонанизированную программу Python, а затем ее демонстративно демонтируйте с помощью supervisord, Это может сэкономить много головных болей и является переносным * nix и языком.
Ответ 6
Вероятно, не прямой ответ на вопрос, но systemd можно использовать для запуска вашего приложения в качестве демона. Вот пример:
[Unit]
Description=Python daemon
After=syslog.target
After=network.target
[Service]
Type=simple
User=<run as user>
Group=<run as group group>
ExecStart=/usr/bin/python <python script home>/script.py
# Give the script some time to startup
TimeoutSec=300
[Install]
WantedBy=multi-user.target
Я предпочитаю этот метод, потому что большая часть работы выполняется для вас, а затем ваш демон script ведет себя аналогично остальной системе.
-Orby
Ответ 7
YapDi - относительно новый модуль python, появившийся в Hacker News. Выглядит довольно полезно, его можно использовать для преобразования python script в режим демона из script.
Ответ 8
поскольку python-daemon еще не поддерживает python 3.x, и из того, что можно прочитать в списке рассылки, он никогда не сможет это сделать, я написал новую реализацию PEP 3143: pep3143daemon
pep3143daemon должен поддерживать как минимум python 2.6, 2.7 и 3.x
Он также содержит класс PidFile.
Библиотека зависит только от стандартной библиотеки и от шести модулей.
Его можно использовать как замену для python-daemon.
Вот документация.
Ответ 9
Эта функция преобразует приложение в демона:
import sys
import os
def daemonize():
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError as err:
sys.stderr.write('_Fork #1 failed: {0}\n'.format(err))
sys.exit(1)
# decouple from parent environment
os.chdir('/')
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError as err:
sys.stderr.write('_Fork #2 failed: {0}\n'.format(err))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, 'r')
so = open(os.devnull, 'w')
se = open(os.devnull, 'w')
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
Ответ 10
Я боюсь, что модуль демона, упомянутый @Dustin, не работал у меня. Вместо этого я установил python-daemon и использовал следующий код:
# filename myDaemon.py
import sys
import daemon
sys.path.append('/home/ubuntu/samplemodule') # till __init__.py
from samplemodule import moduleclass
with daemon.DaemonContext():
moduleclass.do_running() # I have do_running() function and whatever I was doing in __main__() in module.py I copied in it.
Бег легко
> python myDaemon.py
только для полноты здесь приведен пример содержимого каталога образца
>ls samplemodule
__init__.py __init__.pyc moduleclass.py
Содержимое moduleclass.py может быть
class moduleclass():
...
def do_running():
m = moduleclass()
# do whatever daemon is required to do.
Ответ 11
Еще одна вещь, о которой нужно подумать о демонализации в python:
Если вы используете python logging, и вы хотите продолжить его использование после демонстрации, обязательно вызовите close()
для обработчиков (в частности, для обработчиков файлов).
Если вы этого не сделаете, обработчик все равно может подумать, что файлы открыты, а ваши сообщения просто исчезнут - другими словами, убедитесь, что регистратор знает, что его файлы закрыты!
Это предполагает, что когда вы демоннизируете, вы закрываете ВСЕ дескрипторы открытых файлов неизбирательно - вместо этого вы можете попробовать закрыть все, кроме файлов журнала (но обычно проще закрыть все, а затем снова открыть те, которые вы хотите).
Ответ 12
Я изменил несколько строк в примере кода Sander Marechal (упомянутый @JeffBauer в принятом ответе), чтобы добавить метод quit()
, который выполняется перед демоном останавливается. Иногда это очень полезно.
Вот он.
Примечание. Я не использую модуль "python-daemon", потому что документация по-прежнему отсутствует (см. также много других вопросов SO) и довольно неясна (как правильно запустить/остановить демона из командной строки с помощью этого модуля?)
Ответ 13
Хотя вы можете предпочесть чистое решение Python, предоставляемое модулем python-daemon, в libc
есть функция daemon(3)
- по крайней мере, в BSD и Linux - который будет делать правильные вещи.
Вызвать его с python легко:
import ctypes
ctypes.CDLL(None).daemon(0, 0) # Read the man-page for the arguments' meanings
Осталось только создать (и заблокировать) PID файл. Но с этим ты справишься сам...
Ответ 14
Самый простой способ создания демона с Python - использовать Twisted платформу, управляемую событиями. Он обрабатывает все необходимое для демонализации. Он использует Reactor Pattern для обработки параллельных запросов.
Ответ 15
После нескольких лет и многих попыток (я попробовал все ответы, приведенные здесь, но все они имели незначительные недостатки в конце), теперь я понимаю, что есть лучший способ, чем запуск, остановка, перезапуск демона непосредственно из Python.: используйте вместо этого инструменты ОС.
Например, для Linux вместо python myapp start
python myapp stop
я делаю это для запуска приложения:
screen -S myapp python myapp.py
CTRL+A, D to detach
или screen -dmS myapp python myapp.py
чтобы запустить и отключить его одной командой.
Затем:
screen -r myapp
подключить к этому терминалу снова. Оказавшись в терминале, можно использовать CTRL + C, чтобы остановить его.
Ответ 16
80% времени, когда люди говорят "демона", им нужен только сервер. Поскольку вопрос совершенно неясен в этом вопросе, трудно сказать, какова возможная область ответов. Так как сервер достаточно, начните там. Если фактический "демон" действительно необходим (это редко), прочитайте nohup
как способ демонстрации сервера.
До тех пор, пока фактический демон фактически не понадобится, просто напишите простой сервер.
Также рассмотрите описание WSGI.
Также посмотрите Простой HTTP-сервер.
"Есть ли какие-то дополнительные вещи, которые нужно учитывать?" Да. Около миллиона вещей. Какой протокол? Сколько запросов? Как долго обслуживать каждый запрос? Как часто они прибудут? Будете ли вы использовать выделенный процесс? Потоки? Подпроцессы? Написание демона - большая работа.