2010-08-10 91 views
5

我的Python守护进程运行在终端使用此命令我的Ubuntu系统的前景罚款:Python的守护进程不会在Ubuntu后台运行

python /opt/my-daemon.py foreground 

然而,当我尝试调用使用守护“启动”命令失败,为什么?

python /opt/my-daemon.py start 

这是我如何调用在/etc/rc.local文件的命令:

python /opt/my-daemon.py start & 

。由此代码:

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

如果你使用'start'命令会发生什么? – chryss 2010-08-10 12:58:06

+1

“失败”是什么意思? – 2010-08-10 13:00:45

+0

失败,因为根本不运行。它使用前台命令运行。当我在末端用&输入“start”命令时,我看到了PID,但是它立即终止了守护进程。 – QCar 2010-08-10 13:09:08

回答

0

而不是使用daemon.py的,你可能要考虑利用Ubuntu的Upstart system它提供了一个简单的方法来建立一个重生守护进程。从相同的链接,其特点是:

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

如果您使用的Ubuntu9.10或更高版本,看看/etc/init/cron.conf作为一个例子。对于早期版本的Ubuntu,我相信新贵脚本位于/etc/event.d/。

有关Upstart关键字的说明,请参见here

+0

嗨,谢谢你的回答,但我相信我发现了问题,但我会检查出新贵系统。谢谢! – QCar 2010-08-10 13:46:31

1

已解决。我的印象是​​和start参数是两个不同的东西。事实证明,我只需要做到以下几点。

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

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

我然后除去​​参数,因为我可以使用start命令来查看在前景中运行输出来自终端的脚本。

python /opt/my-daemon.py start 

此外,在rc.local我启动脚本如下:

python /opt/my-daemon.py start & 

这个隐藏守护进程和无论谁登录:)

+0

我很高兴你找到了一种让你的程序运行的方式,但只是想你应该知道,通过重写上面描述的'start',你正在切断启动守护进程的daemon.py中的代码。 – unutbu 2010-08-10 14:11:32

+0

重写'start'避免了脚本的早期退出,这表明最初的问题可能在于'Daemon.start'。也许这个pidfile已经存在了?或者'Daemon.daemonize'中的某个内容正在导致提前退出?您可以使用打印语句进行调查,或者尝试使用Upstart。 – unutbu 2010-08-10 14:16:40

+0

@Unutbu谢谢你的回答,我会进一步调查。 – QCar 2010-08-10 14:36:16

相关问题