Проверка состояния процесса с использованием его PID от Python - PullRequest
0 голосов
/ 04 мая 2020

Мой REST API, написанный на Python, порождает процессы, выполнение которых занимает около 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)

1 Ответ

1 голос
/ 05 мая 2020

Вот небольшая симуляция, которая работает:

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.

  • Нужно ли когда-либо очищать QUEUE? Это должно быть убрано? Недостатком является то, что если вы очищаете его после того, как значение было GET один раз, следующее GET извлекает 404. Это проектное решение, если API GET должен быть идемпотентным (скорее всего, да).

...