我用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。如果GET api必须是幂等的(这很可能是),则是设计决策。