2010-08-10 121 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

相關問題