Pregunta

La búsqueda en Google revela fragmentos de código x2. El primer resultado es esta receta de código que tiene mucha documentación y explicación, junto con algunos discusión útil debajo.

Sin embargo, otra muestra de código , aunque no contiene tanta documentación, incluye código de muestra para pasar comandos como iniciar, detener y reiniciar. También crea un archivo PID que puede ser útil para verificar si el demonio ya se está ejecutando, etc.

Estas muestras explican cómo crear el demonio. ¿Hay algo adicional que deba considerarse? ¿Es una muestra mejor que la otra y por qué?

¿Fue útil?

Solución

Solución actual

Una implementación de referencia de PEP 3143 (biblioteca de proceso de daemon estándar) es ahora disponible como python-daemon .

Respuesta histórica

Sander Marechal's código la muestra es superior al original, que se publicó originalmente en 2004. Una vez contribuí con un demonizador para Pyro, pero probablemente usaría el código de Sander si tuviera que hacerlo de nuevo.

Otros consejos

Hay muchas cosas complicadas que debe tener en cuenta al convertirse en un proceso de demonio con buen comportamiento :

  • previene volcados de núcleo (muchos demonios se ejecutan como root, y los volcados de núcleo pueden contener información confidencial)

  • se comporta correctamente dentro de un chroot gaol

  • establezca UID, GID, directorio de trabajo, umask y otros parámetros de proceso de manera apropiada para el caso de uso

  • renunciar a privilegios elevados de suid , sgid privilegios

  • cierra todos los descriptores de archivos abiertos, con exclusiones según el caso de uso

  • se comporta correctamente si se inicia dentro de un contexto ya separado, como init , inetd , etc.

  • configurar controladores de señal para un comportamiento sensible del demonio, pero también con controladores específicos determinados por el caso de uso

  • redirige las transmisiones estándar stdin , stdout , stderr ya que un proceso de daemon ya no tiene un terminal de control

  • maneja un archivo PID como un bloqueo de asesoramiento cooperativo, que es un lata entera de gusanos en sí misma con muchas formas contradictorias pero válidas de comportarse

  • permite una limpieza adecuada cuando el proceso finaliza

  • en realidad se convierte en un proceso demonio sin llevar a zombies

Algunos de estos son estándar , como se describe en la literatura canónica de Unix ( Programación avanzada en el entorno UNIX , por el difunto W. Richard Stevens, Addison-Wesley, 1992 ) Otros, como la redirección de flujo y manejo de archivos PID , son comportamientos convencionales que la mayoría de los usuarios de daemon esperarían pero que están menos estandarizados.

Todos estos están cubiertos por el PEP 3143 & # 8220; Biblioteca de procesos de daemon estándar & # 8221; especificación . La implementación de referencia python-daemon funciona en Python 2.7 o posterior, y Python 3.2 o posterior .

Aquí está mi demonio básico de Python 'Howdy World' con el que empiezo, cuando estoy desarrollando una nueva aplicación de demonio.

#!/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()

Tenga en cuenta que necesitará la biblioteca python-daemon . Puede instalarlo:

pip install python-daemon

Luego, simplemente comience con ./howdy.py start , y deténgalo con ./howdy.py stop .

Tenga en cuenta el paquete python-daemon que resuelve muchos problemas detrás de los demonios de la caja.

Entre otras características que permite (desde la descripción del paquete Debian):

  • Separe el proceso en su propio grupo de procesos.
  • Establecer el entorno de proceso apropiado para ejecutarse dentro de un chroot.
  • Renuncia a los privilegios suid y sgid.
  • Cierre todos los descriptores de archivos abiertos.
  • Cambiar el directorio de trabajo, uid, gid y umask.
  • Establecer manejadores de señal apropiados.
  • Abrir nuevos descriptores de archivo para stdin, stdout y stderr.
  • Administrar un archivo de bloqueo PID especificado.
  • Registrar funciones de limpieza para el procesamiento al salir.

Una alternativa: crear un programa Python normal no demonizado y luego demonizarlo externamente usando supervisor . Esto puede ahorrar muchos dolores de cabeza y es * nix- y el lenguaje portátil.

Probablemente no sea una respuesta directa a la pregunta, pero systemd se puede usar para ejecutar su aplicación como un demonio. Aquí hay un ejemplo:

[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

Prefiero este método porque gran parte del trabajo está hecho para usted, y luego su script daemon se comporta de manera similar al resto de su sistema.

-Orby

dado que python-daemon aún no ha admitido python 3.x, y de lo que se puede leer en la lista de correo, puede que nunca lo haga, he escrito una nueva implementación de PEP 3143: pep3143daemon

pep3143daemon debería admitir al menos Python 2.6, 2.7 y 3.x

También contiene una clase PidFile.

La biblioteca solo depende de la biblioteca estándar y de los seis módulos.

Se puede usar como un reemplazo directo para python-daemon.

Aquí está la documentación .

YapDi es un módulo de Python relativamente nuevo que apareció en Hacker News. Parece bastante útil, se puede usar para convertir un script de Python en modo demonio desde el interior del script.

Esta función transformará una aplicación en un demonio:

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())

Me temo que el módulo demonio mencionado por @Dustin no funcionó para mí. En su lugar, instalé python-daemon y utilicé el siguiente código:

# 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.

Correr es fácil

> python myDaemon.py

solo para completar aquí está el contenido del directorio samplemodule

>ls samplemodule
__init__.py __init__.pyc moduleclass.py

El contenido de moduleclass.py puede ser

class moduleclass():
    ...

def do_running():
    m = moduleclass()
    # do whatever daemon is required to do.

Una cosa más a tener en cuenta al demonizar en Python:

Si está utilizando el registro de Python y desea continuar usándolo después de la demonización, asegúrese de llamar a close () en los controladores (especialmente los controladores de archivos).

Si no hace esto, el controlador aún puede pensar que tiene archivos abiertos, y sus mensajes simplemente desaparecerán; en otras palabras, ¡asegúrese de que el registrador sepa que sus archivos están cerrados!

Esto supone que cuando daemoniza está cerrando TODOS los descriptores de archivos abiertos indiscriminadamente; en su lugar, puede intentar cerrar todos menos los archivos de registro (pero generalmente es más sencillo cerrarlos y volver a abrir los que desee).

Modifiqué algunas líneas en el ejemplo de código de Sander Marechal (mencionado por @JeffBauer en la respuesta aceptada ) para agregar un quit () método que se ejecuta antes de detener el demonio. Esto a veces es muy útil.

Aquí está.

Nota: No uso el " python-daemon " módulo porque todavía falta la documentación (ver también muchas otras preguntas SO) y es bastante oscura (¿cómo iniciar / detener correctamente un demonio desde la línea de comando con este módulo?)

La forma más fácil de crear demonios con Python es utilizar el Twisted marco controlado por eventos. Maneja todas las cosas necesarias para la demonización para ti. Utiliza el Patrón de Reactor para manejar solicitudes concurrentes.

Después de algunos años y muchos intentos (probé todas las respuestas aquí, pero todas tenían inconvenientes menores al final), ahora me doy cuenta de que hay una mejor manera que querer comenzar, detener y reiniciar un demonio directamente desde Python: use las herramientas del sistema operativo en su lugar.

Por ejemplo, para Linux, en lugar de hacer python myapp start y python myapp stop , hago esto para iniciar la aplicación:

screen -S myapp python myapp.py    
CTRL+A, D to detach
Pantalla

o -dmS myapp python myapp.py para iniciar y separarlo en un comando .

Entonces:

screen -r myapp

para conectar a este terminal nuevamente. Una vez en el terminal, es posible usar CTRL + C para detenerlo.

El 80% del tiempo, cuando la gente dice "daemon", solo quieren un servidor. Dado que la pregunta no es clara en este punto, es difícil decir cuál podría ser el posible dominio de respuestas. Como un servidor es adecuado, comience allí. Si un "demonio" real es realmente necesario (esto es raro), lea en nohup como una forma de demonizar un servidor.

Hasta que se requiera un demonio real, simplemente escriba un servidor simple.

Observe también la implementación referencia WSGI .

También mire el Servidor HTTP simple .

" ¿Hay algo adicional que deba considerarse? " Sí. Alrededor de un millón de cosas. Que protocolo Cuantas solicitudes ¿Cuánto tiempo para atender cada solicitud? ¿Con qué frecuencia llegarán? ¿Usarás un proceso dedicado? ¿Trapos? Subprocesos? Escribir un demonio es un gran trabajo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top