使用来自 Python 的 PID 检查进程的状态
Checking the status of a process using its PID from Python
我用 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 的部署可以有多个 worker,每个 worker 都有自己的全局变量。因此,为了扩大规模,请考虑改用 redis / mq 数据存储。
队列是否需要清理?该不该清理?它有一个缺点,如果你在值被 GET 一次后清理它,下一个 GET 获取 404。如果 GET api 必须是幂等的(很可能是),这是一个设计决定。
我用 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 的部署可以有多个 worker,每个 worker 都有自己的全局变量。因此,为了扩大规模,请考虑改用 redis / mq 数据存储。
队列是否需要清理?该不该清理?它有一个缺点,如果你在值被 GET 一次后清理它,下一个 GET 获取 404。如果 GET api 必须是幂等的(很可能是),这是一个设计决定。