使用Python中的PID检查进程的状态



用Python编写的我的REST API生成大约需要3分钟才能完成的进程。我将PID存储在一个全局数组中,并设置一个辅助检查方法,用于确认进程是否仍在运行,或者是否已完成。

我能找到的唯一方法是轮询子流程(在这个路由中我无法访问(,或者尝试终止流程以查看它是否有效。有没有什么干净的方法可以得到一个二进制答案,即它是否仍在基于PID运行,如果没有,它是否成功完成?

from flask import Flask, jsonify, request, Response
from subprocess import Popen, PIPE
import os
app = Flask(__name__)
QUEUE_ID = 0
jobs = []
@app.route("/compile", methods=["POST"])
def compileFirmware():
f = request.files['file']
f.save(f.filename)
os.chdir("/opt/src/2.0.x")
process = Popen(['platformio', 'run', '-e', 'mega2560'], stdout=PIPE, stderr=PIPE, universal_newlines=True)
global QUEUE_ID
QUEUE_ID += 1
data = {'id':QUEUE_ID, 'pid':process.pid}
jobs.append(data)
output, errors = process.communicate()
print (output)
print (errors)
response = jsonify()
response.status_code = 202 #accepted
response.headers['location'] = '/queue/' + str(QUEUE_ID)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
@app.route("/queue/<id>", methods=["GET"])
def getStatus(id):
#CHECK PID STATUS HERE
content = {'download_url': 'download.com'}
response = jsonify(content)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8080)

这里有一个有效的小模拟:

from flask import Flask, jsonify, request, Response, abort
from subprocess import Popen, PIPE
import os
app = Flask(__name__)
QUEUE = { }
@app.route("/compile", methods=["POST"])
def compileFirmware():
process = Popen(['python','-c','"import time; time.sleep(300)"'], stdout=PIPE, stderr=PIPE, universal_newlines=True)
QUEUE[str(process.pid)] = process # String because in GET the url param will be interpreted as str
response = jsonify()
response.status_code = 202 #accepted
response.headers['location'] = '/queue/' + str(process.pid)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
@app.route("/queue/<id>", methods=["GET"])
def getStatus(id):
process = QUEUE.get(id, None)
if process is None:
abort(404, description="Process not found")
retcode = process.poll()
if retcode is None:
content = {'download_url': None, 'message': 'Process is still running.'}
else:
# QUEUE.pop(id) # Remove reference from QUEUE ?
content = {'download_url': 'download.com', 'message': f'process has completed with retcode: {retcode}'}
response = jsonify(content)
response.headers.add('Access-Control-Allow-Origin', '*')
return response
if __name__ == '__main__':
app.run(host='0.0.0.0',port=8080)

如果这个应用程序要作为一个单独的项目使用,还需要进一步考虑。

  • 我们使用QUEUE全局变量来存储进程的状态。但在实际项目中,通过wsgi/gunicorn进行的部署可以有多个工作者,每个工作者都有自己的全局变量。因此,要进行扩展,请考虑使用redis/mq数据存储。

  • 队列是否需要清理?应该清理一下吗?它的缺点是,如果在值被GET一次之后对其进行清理,那么下一个GET将获取404。GETAPI是否必须是幂等的(很可能是(,这是一个设计决策。

最新更新