2010-08-10 6 views
5

Mi Python daemon funciona muy bien en el primer plano de mi sistema Ubuntu usando este comando en el terminal:demonio de Python no se ejecutará en segundo plano en Ubuntu

python /opt/my-daemon.py foreground 

Sin embargo cuando intento llamar al demonio con el El comando "start" falla, ¿por qué?

python /opt/my-daemon.py start 

Esta es la forma en que llamo el comando en el archivo /etc/rc.local:

python /opt/my-daemon.py start & 

adjunto el código:

1.daemon.py

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

2 .my-daemon.py

import sys, time 
from daemon import Daemon 
import MySQLdb #MySQL libraries 
#Database parameters 
config = {"host":"localhost",...} 
try: 
    conn = MySQLdb.connect(config['host'],... 
class MyDaemon(Daemon): 
def run(self): 
    while True: 
     time.sleep(2) 
        #{Do processes, connect to the database, etc....} 
        ... 
if __name__ == "__main__": 
daemon = MyDaemon('/tmp/daemon-example.pid') 
if len(sys.argv) == 2: 
    if 'start' == sys.argv[1]: 
     daemon.start() 
    elif 'stop' == sys.argv[1]: 
     daemon.stop() 
    elif 'restart' == sys.argv[1]: 
     daemon.restart() 
    elif 'foreground' == sys.argv[1]: #This runs the daemon in the foreground 
     daemon.run() 
    else: 
     print "Unknown command" 
     sys.exit(2) 
    sys.exit(0) 
else: 
    print "usage: %s start|foreground|stop|restart" % sys.argv[0] 
    sys.exit(2) 
+0

¿Qué ocurre exactamente si usa el comando 'start'? – chryss

+1

¿Qué quiere decir con "falla"? –

+0

falla como no funciona en absoluto. Se ejecuta con el comando de primer plano. Cuando escribo el comando "inicio" en el terminal con el & al final veo el PID, pero inmediatamente mata el proceso del daemon. – QCar

Respuesta

0

En lugar de utilizar daemon.py, es posible que desee considerar el aprovechamiento de Upstart system que proporciona una manera fácil de configurar un demonio respawning Ubuntu. Del mismo enlace, que cuenta con:

* Services may be respawned if they die unexpectedly 
* Supervision and respawning of daemons which separate from their parent process 

Si está utilizando Ubuntu9.10 o temprano, echar un vistazo a /etc/init/cron.conf como un ejemplo. Para las versiones anteriores de Ubuntu, creo que las secuencias de comandos upstart se encuentran en /etc/event.d/.

Para obtener una explicación de las palabras clave de Upstart, consulte here.

+0

Hola, gracias por su respuesta, pero creo que encontré el problema, pero verificará el sistema advenedizo. ¡Gracias! – QCar

1

SOLUCIONADO. Tenía la impresión de que el parámetro foreground y el start eran dos cosas diferentes. Resulta que solo necesitaba hacer lo siguiente.

def run(self): 
    while True: 
     time.sleep(2) 

a

def start(self): 
    while True: 
     time.sleep(2) 

que luego se retira el parámetro foreground, porque puedo ejecutar la secuencia de comandos de la terminal con el comando start para ver la salida en el primer plano.

python /opt/my-daemon.py start 

Además, en rc.local comienzo a la secuencia de comandos de la siguiente manera:

python /opt/my-daemon.py start & 

Esto oculta el proceso de demonio y ejecuta la secuencia de comandos en el arranque, independientemente del usuario que se registra :)

+0

Me alegro de que hayas encontrado la forma de ejecutar tu programa, pero pensé que deberías saber que al anular 'start' como describes arriba, estás cortando el código en daemon.py que inicia el daemon. – unutbu

+0

Ese 'inicio' invalidante evita la salida anticipada de su secuencia de comandos sugiere que el problema original probablemente se encuentre en 'Daemon.start'. Quizás el archivo pidfile ya existe? o algo en 'Daemon.daemonize' está causando la salida anticipada? Puede usar las declaraciones de impresión para investigar, o quizás pruebe Upstart en su lugar. – unutbu

+0

@Unutbu Gracias por todas sus respuestas, investigaré más a fondo. – QCar

Cuestiones relacionadas