script run example daemonize python linux scripting daemons

run - Cómo hacer que un script de Python se ejecute como un servicio o daemon en Linux



python-daemon example (15)

He escrito un script de Python que verifica una cierta dirección de correo electrónico y pasa nuevos correos electrónicos a un programa externo. ¿Cómo puedo hacer que este script se ejecute 24/7, como convertirlo en daemon o servicio en Linux? ¿También necesitaría un bucle que nunca termina en el programa, o puede hacerse simplemente haciendo que el código se ejecute varias veces?


¿Qué hay de usar el comando $nohup en Linux?

Lo uso para ejecutar mis comandos en mi servidor Bluehost.

Por favor, consejo si estoy equivocado.


Aquí hay una buena clase que se toma de here :

#!/usr/bin/env python import sys, os, time, atexit from signal import SIGTERM class Daemon: """ A generic daemon class. Usage: subclass the Daemon class and override the run() method """ def __init__(self, pidfile, stdin=''/dev/null'', stdout=''/dev/null'', stderr=''/dev/null''): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile def daemonize(self): """ do the UNIX double-fork magic, see Stevens'' "Advanced Programming in the UNIX Environment" for details (ISBN 0201563177) http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 """ try: pid = os.fork() if pid > 0: # exit first parent sys.exit(0) except OSError, e: sys.stderr.write("fork #1 failed: %d (%s)/n" % (e.errno, e.strerror)) 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, e: sys.stderr.write("fork #2 failed: %d (%s)/n" % (e.errno, e.strerror)) sys.exit(1) # redirect standard file descriptors sys.stdout.flush() sys.stderr.flush() si = file(self.stdin, ''r'') so = file(self.stdout, ''a+'') se = file(self.stderr, ''a+'', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) # write pidfile atexit.register(self.delpid) pid = str(os.getpid()) file(self.pidfile,''w+'').write("%s/n" % pid) def delpid(self): os.remove(self.pidfile) def start(self): """ Start the daemon """ # Check for a pidfile to see if the daemon already runs try: pf = file(self.pidfile,''r'') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon already running?/n" sys.stderr.write(message % self.pidfile) sys.exit(1) # Start the daemon self.daemonize() self.run() def stop(self): """ Stop the daemon """ # Get the pid from the pidfile try: pf = file(self.pidfile,''r'') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile %s does not exist. Daemon not running?/n" sys.stderr.write(message % self.pidfile) return # not an error in a restart # Try killing the daemon process try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) except OSError, err: err = str(err) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print str(err) sys.exit(1) def restart(self): """ Restart the daemon """ self.stop() self.start() def run(self): """ You should override this method when you subclass Daemon. It will be called after the process has been daemonized by start() or restart(). """


Deberías usar la biblioteca python-daemon , se ocupa de todo.

Desde PyPI: Library para implementar un proceso de demonio Unix con buen comportamiento.


Para crear algo que se ejecuta como servicio, puede usar esta cosa:

Lo primero que debe hacer es instalar el marco Cement : el trabajo de marco de cemento es un trabajo de marco CLI que puede implementar su aplicación en él.

interfaz de línea de comando de la aplicación:

interface.py

from cement.core.foundation import CementApp from cement.core.controller import CementBaseController, expose from YourApp import yourApp class Meta: label = ''base'' description = "your application description" arguments = [ ([''-r'' , ''--run''], dict(action=''store_true'', help=''Run your application'')), ([''-v'', ''--version''], dict(action=''version'', version="Your app version")), ] ([''-s'', ''--stop''], dict(action=''store_true'', help="Stop your application")), ] @expose(hide=True) def default(self): if self.app.pargs.run: #Start to running the your app from there ! YourApp.yourApp() if self.app.pargs.stop: #Stop your application YourApp.yourApp.stop() class App(CementApp): class Meta: label = ''Uptime'' base_controller = ''base'' handlers = [MyBaseController] with App() as app: app.run()

Clase YourApp.py:

import threading class yourApp: def __init__: self.loger = log_exception.exception_loger() thread = threading.Thread(target=self.start, args=()) thread.daemon = True thread.start() def start(self): #Do every thing you want pass def stop(self): #Do some things to stop your application

Tenga en cuenta que su aplicación debe ejecutarse en un hilo para ser demonio

Para ejecutar la aplicación solo haz esto en la línea de comando

python interface.py --ayuda


Primero, lee los alias del correo. Un alias de correo hará esto dentro del sistema de correo sin que tengas que perder el tiempo con daemons o servicios o algo por el estilo.

Puede escribir un script simple que sendmail ejecutará cada vez que se envíe un mensaje de correo a un buzón específico.

Ver http://www.feep.net/sendmail/tutorial/intro/aliases.html

Si realmente desea escribir un servidor innecesariamente complejo, puede hacerlo.

nohup python myscript.py &

Eso es todo lo que se necesita. Tu script simplemente se repite y duerme.

import time def do_the_work(): # one round of polling -- checking email, whatever. while True: time.sleep( 600 ) # 10 min. try: do_the_work() except: pass


Puede usar fork () para separar su script del tty y hacer que continúe ejecutándose, de esta forma:

import os, sys fpid = os.fork() if fpid!=0: # Running as daemon now. PID is fpid sys.exit(0)

Por supuesto, también necesita implementar un bucle infinito, como

while 1: do_your_check() sleep(5)

Espero que esto empiece.


Si está usando terminal (ssh o algo así) y desea mantener un script de larga duración en funcionamiento después de cerrar la sesión desde el terminal, puede intentar esto:

screen

apt-get install screen

crear una terminal virtual dentro (a saber, abc): screen -dmS abc

ahora nos conectamos a abc: screen -r abc

Entonces, ahora podemos ejecutar el script de python Keep_sending_mail.py : python Keep_sending_mail.py

a partir de ahora, puede cerrar directamente su terminal, sin embargo, la secuencia de comandos python seguirá ejecutándose en lugar de cerrarse

Dado que este PID de Keep_sending_mail.py pertenece a la pantalla virtual en lugar de a la terminal (ssh)

Si quieres volver verifica el estado de ejecución de tu script, puedes usar screen -r abc otra vez


También puede hacer que el script python se ejecute como un servicio utilizando un script de shell. Primero crea un script de shell para ejecutar el script de python así (nombre de script nombre arbitario)

#!/bin/sh script=''/home/.. full path to script'' /usr/bin/python $script &

ahora crea un archivo en /etc/init.d/scriptname

#! /bin/sh PATH=/bin:/usr/bin:/sbin:/usr/sbin DAEMON=/home/.. path to shell script scriptname created to run python script PIDFILE=/var/run/scriptname.pid test -x $DAEMON || exit 0 . /lib/lsb/init-functions case "$1" in start) log_daemon_msg "Starting feedparser" start_daemon -p $PIDFILE $DAEMON log_end_msg $? ;; stop) log_daemon_msg "Stopping feedparser" killproc -p $PIDFILE $DAEMON PID=`ps x |grep feed | head -1 | awk ''{print $1}''` kill -9 $PID log_end_msg $? ;; force-reload|restart) $0 stop $0 start ;; status) status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $? ;; *) echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}" exit 1 ;; esac exit 0

Ahora puede iniciar y detener su script de python usando el comando /etc/init.d/scriptname start o stop.


Tienes dos opciones aquí.

  1. Haga un trabajo cron apropiado que llame a su script. Cron es un nombre común para un daemon de GNU / Linux que periódicamente lanza secuencias de comandos de acuerdo con un programa establecido. Agregue su secuencia de comandos en un crontab o coloque un enlace simbólico en un directorio especial y el daemon maneja el trabajo de iniciarlo en segundo plano. Puedes leer más en wikipedia. Existe una variedad de diferentes daemons cron, pero su sistema GNU / Linux debería tenerlo ya instalado.

  2. Utilice algún tipo de enfoque de Python (una biblioteca, por ejemplo) para que su script pueda demonizarse a sí mismo. Sí, requerirá un bucle de evento simple (donde sus eventos son disparadores de temporizador, posiblemente proporcionados por la función de suspensión).

No recomendaría que eligieras 2. porque de hecho estás repitiendo la funcionalidad de cron. El paradigma del sistema Linux es permitir que múltiples herramientas simples interactúen y resuelvan sus problemas. A menos que haya razones adicionales por las que debe crear un daemon (además de activarse periódicamente), elija el otro enfoque.

Además, si utiliza daemonize con un bucle y se produce un bloqueo, nadie revisará el correo después de eso (como señaló Ivan Nevostruev en los comentarios a this respuesta). Si bien la secuencia de comandos se agrega como una tarea cron, simplemente se activará nuevamente.



Una versión simple y supported es Deamonize. Instálala desde el Python Package Index (PyPI):

$ pip install daemonize

y luego usar como:

... import os, sys from daemonize import Daemonize ... def main() # your code here if __name__ == ''__main__'': myname=os.path.basename(sys.argv[0]) pidfile=''/tmp/%s'' % myname # any name daemon = Daemonize(app=myname,pid=pidfile, action=main) daemon.start()


Utilice el administrador de servicios que su sistema le ofrezca, por ejemplo, en Ubuntu use upstart . Esto manejará todos los detalles para usted, como inicio al arrancar, reinicio en crash, etc.


Yo recomendaría esta solución. Debe heredar y anular la run método.

import sys import os from signal import SIGTERM from abc import ABCMeta, abstractmethod class Daemon(object): __metaclass__ = ABCMeta def __init__(self, pidfile): self._pidfile = pidfile @abstractmethod def run(self): pass def _daemonize(self): # decouple threads pid = os.fork() # stop first thread if pid > 0: sys.exit(0) # write pid into a pidfile with open(self._pidfile, ''w'') as f: print >> f, os.getpid() def start(self): # if daemon is started throw an error if os.path.exists(self._pidfile): raise Exception("Daemon is already started") # create and switch to daemon thread self._daemonize() # run the body of the daemon self.run() def stop(self): # check the pidfile existing if os.path.exists(self._pidfile): # read pid from the file with open(self._pidfile, ''r'') as f: pid = int(f.read().strip()) # remove the pidfile os.remove(self._pidfile) # kill daemon os.kill(pid, SIGTERM) else: raise Exception("Daemon is not started") def restart(self): self.stop() self.start()



cron es claramente una gran opción para muchos propósitos. Sin embargo, no crea un servicio o daemon como solicitó en el OP. cron simplemente ejecuta trabajos periódicamente (lo que significa que el trabajo comienza y se detiene), y no más de una vez / minuto. Hay problemas con cron : por ejemplo, si una instancia anterior de su script aún se está ejecutando la próxima vez que aparece el cronograma cron y se inicia una nueva instancia, ¿está bien? cron no maneja dependencias; solo trata de comenzar un trabajo cuando el horario lo dice.

Si encuentra una situación en la que realmente necesita un daemon (un proceso que nunca deja de ejecutarse), eche un vistazo a supervisord . Proporciona una forma simple de envolver un script o programa normal no dañado y hacerlo funcionar como un daemon. Esta es una forma mucho mejor que crear un demonio Python nativo.