从Python启动守护进程,然后从父进程中分离父进程

时间:2013-10-14 21:33:22

标签: python

我在远程计算机上运行守护程序: mydaemon 。该守护进程应始终持续运行。

当我在远程计算机上运行作业时,它还会启动一个轻量级的python服务器进程 my_remote_server.py

我可以发送到 my_remote_server.py 的其中一个命令是重启 mydaemon ,我正试图这样做:

os.system("killall mydaemon")
subprocess.Popen(["mydaemon"], stdin=None, stdout=None, stderr=None, close_fds=True)

当我的工作结束时, my_remote_server.py 应该终止,但 mydaemon 应该继续运行。但是我看到 my_remote_server.py 卡在僵尸进程中(这导致系统看不到我的作业被终止)

  820 root            Z   [my_remote_serve]
  834 root        552 S   /usr/sbin/telnetd -l /bin/sh 
  835 root        836 S   /bin/sh 
  844 root        672 S   mydaemon 

我想从孩子( mydaemon )中分离父母( my_remote_server.py ),但我无法弄清楚如何。

- 我的python版本是2.5.4

编辑:

我认为我现在更了解守护进程,但是我仍然无法让守护进程分离

我为了简洁而省略了错误处理

os.system("killall mydaemon")

if(os.fork() > 0):
    return True # my_remote_server.py returns to handle additional commands

os.setsid()
if(os.fork() > 0):
    exit(0) # first child exits after becoming session leader

os.execlp("mydaemon") # have the second child run as the daemon

在我调用restart_mydaemon函数

之前,这是我的ps列表
252 root        672 S   mydaemon
286 root       4552 S   /usr/bin/python my_remote_server.py

这是在restart_mydaemon之后,第一个孩子被僵尸(不应该消失吗?)

286 root       4552 S   /usr/bin/python my_remote_server.py
300 root            Z   [my_remote_serve]
304 root        672 S   [mydaemon]

这是作业终止的时候(my_remote_server.py应该已经退出,但是它是一个僵尸,但是,现在第一个孩子已经退出了)

286 root            Z   [my_remote_serve]
304 root       1012 S   [mydaemon]

3 个答案:

答案 0 :(得分:1)

将进程转换为守护进程是一个多步骤的过程。您的部分问题是您的父进程没有正确等待子终止(请参阅wait / waitpid),

  • 您的进程必须关闭所有打开的文件描述符(stdin,stdout,stderr)
  • 您的流程需要(更改目录,设置umask,无论您想要/需要什么)
  • 你必须分叉一个过程
  • 该流程必须成为流程组负责人
  • 你必须再次分叉,以完全脱离(大)父母

    try:
        #free parent, detach from process group
        pid = os.fork()
        if( pid>0 ):
            exit(0) #parent exits
    except OSError, e:
        raise Exception("%s [%d]" % (e.strerror, e.errno))
    #become session leader, process group leader, detach from controlling terminal
    os.setsid()
    try:
        #prevent zombie process, make init cleanup
        pid = os.fork()
        if( pid>0 ):
            exit(0) #parent exits
    except OSError, e:
        raise Exception("%s [%d]" % (e.strerror, e.errno))
    #change directories, close stdin/out/err, etc
    os.chdir(MYDIR)
    os.umask(MYMASK)
    #close files (including stdin, stdout, stderr)
    #(re)open new stdin/stdout, if desired
    

答案 1 :(得分:0)

请查看此处以获取有关守护程序如何工作的参考/良好解释:

http://code.activestate.com/recipes/278731/

总的来说这非常重要,我会尝试使用python-daemon库或类似的库:

https://pypi.python.org/pypi/python-daemon/

答案 2 :(得分:0)

我不会调用子进程来执行此操作。子进程imo仅应用于运行无法导入的命令。

因此,在这种情况下,您的my_remote_server.py可以导入mydaemon并运行它。

您有2种方法可以做到这一点。您可以将my_remote_server设置为父级,将mydaemon设置为子级。或有一个新的脚本作为父脚本并生成2个子脚本(mydaemon,my_remote_server)。

例如。在下面,我创建一个子进程。全局范围,因为我需要在龙卷风的HTTP处理程序中访问它。我设置了Web服务器。启动子进程,然后启动Web服务器。命中端点后,处理程序将运行,并将子进程从全局范围中拉出。我们终止子进程并打印。您可以向龙卷风添加更多终结点,以再次启动子级,或者停止然后重新启动它。

remote.py:

import multiprocessing
import deamon
import tornado.ioloop
import tornado.web

child_pro = multiprocessing.Process(target=deamon.run_deamon)
child_pro.daemon = True


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        global child_pro
        child_pro = child_pro  # type: multiprocessing.Process
        child_pro.terminate()
        print ("Child killed")


def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])


if __name__ == "__main__":
    global child_pro
    app = make_app()
    app.listen(8888)
    child_pro.start()
    tornado.ioloop.IOLoop.current().start()

deamon.py:

import time


def run_deamon():
    while True:
        time.sleep(2)
        print ('child alive')