python-daemon启动一个独立的进程,但让主应用程序继续?

时间:2017-08-29 18:53:27

标签: python

好吧,在运行我可以在google上找到的每个样本后,我正式完成了想法,直到第19页。我有一个“提供者”脚本。这个python脚本的目标是启动其他服务,即使在此“提供程序”停止运行后也无限期运行。基本上,启动过程然后忘记它,但继续脚本而不是停止它...

我的问题:python-daemon ...我有动作(从启动的服务启动/停止/获取状态的Web服务调用)。我会动态创建启动命令,并根据需要对配置文件执行变量替换。

让我们从这一点开始:我有一个运行命令(一个执行java进程的bash脚本 - 一个将在稍后停止的长时间运行的服务)。

def start(command, working_directory):
    pidfile = os.path.join(working_directory, 'application.pid') 
    # I expect the pid of the started application to be here. The file is not created. Nothing is there.

    context = daemon.DaemonContext(working_directory=working_directory,
                                   pidfile=daemon.pidfile.PIDLockFile(pidfile))
    with context:
        psutil.Popen(command)

    # This part never runs. Even if I put a simple print statement at this point, that never appears. Debugging in pycharms shows that my script returns with 0 on with context
    with open(pidfile, 'r') as pf:
        pid = pf.read()

    return pid

从我的调用者到这个方法,我准备一个json对象返回到客户端,它基本上包含一个instance_id(不介意)和一个pid(它将用于在另一个请求中停止这个进程)

会发生什么?在使用上下文后,我的应用程序以状态0退出,没有返回任何内容,也没有创建json响应,只有执行的psutil.Popen命令运行才会创建pidfile。我怎样才能达到我的需要?我需要一个独立运行的进程,需要知道它的PID,以便以后停止它。即使当前python脚本由于某种原因停止,执行的进程也必须运行。我无法绕过shell脚本,因为该应用程序不是我的,我必须使用我拥有的。

感谢任何提示!

@Edit: 我尝试使用psutil / subprocess中的Popen,结果更有希望。

def start(self, command):
    import psutil/subprocess

    proc = psutil.Popen(command)

    return str(proc.pid)

现在如果我调试应用程序并在return语句上等待一些未定义的时间,一切都很好!该服务正在运行pid,我可以稍后停止。然后我只是运行提供程序而不进行调试。它返回pid,但进程未运行。似乎Popen没有时间启动服务,因为整个提供商停止更快。

@Update: 使用os.fork:

@staticmethod
def __start_process(command, working_directory):
    pid = os.fork()
    if pid == 0:
        os.chdir(working_directory)
        proc = psutil.Popen(command)
        with open('application.pid', 'w') as pf:
            pf.write(proc.pid)

def start(self):
    ...
    __start_process(command, working_directory)
    with open(os.path.join(working_directory, 'application.pid'), 'r') as pf:
        pid = int(pf.read())

    proc = psutil.Process(pid)
    print("RUNNING" if proc.status() == psutil.STATUS_RUNNING else "...")

运行上面的示例后,RUNNING将写入控制台。主脚本退出后,因为我不够快:

  

ps auxf | grep的   没有实例正在运行......

检查pid文件;确定它在那里创建了

  

cat /application.pid   EMPTY 0bytes

2 个答案:

答案 0 :(得分:1)

您是否尝试过os.fork()

简而言之,os.fork()会生成一个新进程并返回该新进程的PID。

你可以这样做:

#!/usr/bin/env python

import os
import subprocess
import sys
import time

command = 'ls' # YOUR COMMAND
working_directory = '/etc' #  YOUR WORKING DIRECTORY

def child(command, directory):
    print "I'm the child process, will execute '%s' in '%s'" % (command, directory)
    # Change working directory
    os.chdir(directory)
    # Execute command
    cmd = subprocess.Popen(command
        , shell=True
        , stdout=subprocess.PIPE
        , stderr=subprocess.PIPE
        , stdin=subprocess.PIPE
    )
    # Retrieve output and error(s), if any
    output = cmd.stdout.read() + cmd.stderr.read()
    print output
    # Exiting
    print 'Child process ending now'
    sys.exit(0)

def main():
    print "I'm the main process"
    pid = os.fork()
    if pid == 0:
        child(command, working_directory)
    else:
        print 'A subprocess was created with PID: %s' % pid
        # Do stuff here ...
        time.sleep(5)
        print 'Main process ending now.'
        sys.exit(0)

if __name__ == '__main__':
    main()

更多信息:

答案 1 :(得分:1)

从我得到的多个部分提示,终于设法让它工作......

def start(command, working_directory):
    pid = os.fork()
    if pid == 0:
        os.setsid()
        os.umask(0) # I'm not sure about this, not on my notebook at the moment
        os.execv(command[0], command) # This was strange as i needed to use the name of the shell script twice: command argv[0] [args]. Upon using ksh as command i got a nice error...
    else:
        with open(os.path.join(working_directory, 'application.pid'), 'w') as pf:
            pf.write(str(pid))

        return pid

这一起解决了这个问题。启动的进程不是正在运行的python脚本的子进程,并且在脚本终止时不会停止。