我正在尝试从我的Flask网络应用程序启动和管理一些流程。我希望能够启动一个进程并能够终止/终止它。
在我的例子中,testscript.sh只是睡了10秒钟。
我的类processManager实现了Borg设计模式,试图解决我的问题,但它没有改变任何东西。 (事先,我的进程,锁和线程变量只是全局变量,而processManager根本就不是一个类。)
processes属性是所有已启动进程的列表。
addProcess启动一个新进程,将其添加到进程。它查看轮询线程是否正在运行,如果不是则启动它。
轮询线程轮询进程列表中的所有进程,并检查其退出状态是否已更改。如果所有进程都完成,则线程停止。
stopProcess循环遍历进程以找到正确的进程并终止它。
class Borg:
_shared_state = {}
def __init__(self):
self.__dict__ = self._shared_state
# Pokes the processes to see their exit status. Stops when there is no running thread left.
class processManager(Borg):
class pollProcesses (threading.Thread):
def __init__(self, pManager):
threading.Thread.__init__(self)
self.pManager = pManager
def run(self):
while True:
#poll exit codes:
#None Running
#0 Finished nicely
#-n terminated by signal n
time.sleep(1)
pprint.pprint("-----------")
self.pManager.lock.acquire()
stop = True
for p in self.pManager.processes:
status = p.poll()
pprint.pprint(str(p.jobid)+" "+str(p.pid)+" "+str(status))
if status is None:
stop = False
#else log process status somewhere
self.pManager.lock.release()
if stop:
pprint.pprint("-----------")
pprint.pprint("No process running, stopping scan.")
break;
def __init__(self):
Borg.__init__(self)
pprint.pprint("New instance!")
if not hasattr(self, "processes"):
pprint.pprint("FIRST instance!")
self.processes = []
if not hasattr(self, "lock"):
self.lock = threading.Lock()
if not hasattr(self, "thread"):
self.thread = None
def addProcess(self, job):
pprint.pprint("-----------")
path = os.path.realpath(__file__)
pprint.pprint("Adding new process")
p = Popen(["/path/to/testscript.sh"], shell=True)
p.jobid = job['id']
# Lock the processes list before adding data
self.lock.acquire()
self.processes.append(p)
#If thread is finished, start it up
if self.thread is None or not self.thread.isAlive():
pprint.pprint("Starting thread")
self.thread = None
self.thread = self.pollProcesses(self)
self.thread.start()
pprint.pprint(self.thread)
self.lock.release()
return
def stopProcess(self, jobid):
pprint.pprint("STOP job"+str(jobid))
self.lock.acquire()
pprint.pprint(self.thread)
pprint.pprint("Jobs in processes:")
for p in self.processes:
pprint.pprint(p.jobid)
if p.jobid == jobid:
p.terminate()
self.lock.release()
return
在烧瓶应用程序中,我基本上做了这样的事情:
@plugin.route('/startjob', methods=['GET'])
def startJob():
if not hasattr(g, "pManager"):
g.pManager = processManager()
#SNIP - create/obtain job
g.pManager.addProcess(job)
return "OK"
与停止工作相似的东西。
现在,如果我启动一项工作并尝试从我的Flask应用程序停止它,有时进程列表将创建一个全新的Borg / processManager(打印“FIRST实例!”)
从那时起,一切都变得无法预测:
即使来自两个线程和两个不同的进程列表,我的进程状态仍在更新。这不是我的目标,但它确实有效。
但是如果我想停止一个进程,stopProcess函数可能是“错误的”,因为现在有几个具有不同进程列表的processManager,我无法知道被调用的stopProcess函数是否有访问权限。我希望停止特定的过程。
我认为这可能是由mod_wsgi或apache引起的,其多线程/多处理机制导致我的processManager在完全不同的上下文中运行。
我希望processManager的进程列表,锁和线程是相同的,无论mod_wsgi进程正在访问它。
我仍然是python的新手,所以我的问题可能完全不同。任何帮助表示赞赏。
请记住,这是简化的代码,它仍然会重现问题,但它确实没有做太多。
答案 0 :(得分:2)
通常,从Web应用程序创建子进程不是一个好主意,因为它可能会导致各种问题,具体取决于所使用的Web服务器。由于使用多进程Web服务器配置,从父进程继承奇数信号掩码等问题,可能会出现问题。
如果您想创建作业来执行某些任务,那么使用专门构建的任务排队系统(例如Celery,Redis Queue(RQ),gearman或类似工具)可能会更好。