Flask, processing requests 1 by 1

ぐ巨炮叔叔 提交于 2021-01-21 04:11:14

问题


I have a flask application which listens for some job to do. The process is quite long (let us say 1 minute) and I would like not allow to process two requests at the same time.

I will be great if once I receive a request, I could close the port flask is listening to and open again when finish. Alternatively I could setup a semaphore but I am not sure about how flask is running concurrently.

Any advice?

from flask import Flask, request
app = Flask(__name__)

@app.route("/",methods=['GET'])
def say_hi():
    return "get not allowed"

@app.route("/",methods=['POST'])
def main_process():
    # heavy process here to run alone
    return "Done"

if __name__ == "__main__":
    app.run(debug=True,host='0.0.0.0')

回答1:


You could use a semaphore for this:

import threading
import time
sem = threading.Semaphore()

@app.route("/",methods=['POST'])
def main_process():
    sem.acquire()
    # heavy process here to run alone
    sem.release()
    return "Done"

The semaphore usage is to control the access to a common resource.

You can see more info about semaphore in here

This SO question can help you as well here

EDIT:

As Georg Schölly wrote in comment, The above mentioned solution is problematic in a situation of multiple services.

Although, you can use the wsgi in order to accomplish your goal.

@app.route("/",methods=['POST'])
def main_process():
    uwsgi.lock()
    # Critical section
    # heavy process here to run alone
    uwsgi.unlock()
    return "Done"

uWSGI supports a configurable number of locks you can use to synchronize worker processes

For more info, read here




回答2:


You could try adding a threading.Lock to indicate that some work is already in progress:

import threading
from contextlib import ExitStack

busy = threading.Lock()
@app.route("/",methods=['POST'])
def main_process():
    if not busy.acquire(timeout = 1):
        return 'The application is busy, refresh the page in a few minutes'

    # ensure busy.release() is called even if an exception is thrown
    with ExitStack() as stack:
        stack.callback(busy.release)
        # heavy process here to run alone

    return "Done"

But Flask by default allows only one request to be processed at a time (more info here), so if you're fine with the fact that during the processing of a single request, all the other users' pages won't load until the process is finished (maybe even get a request timeout error), you don't have to change anything.
If you want to make other users get a message, like in the above code, increase the amount of workers to 2, so that when one worker processes the request, the other one holds off the others.



来源:https://stackoverflow.com/questions/42325105/flask-processing-requests-1-by-1

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!