Reputation: 738
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')
Upvotes: 18
Views: 18213
Reputation: 10621
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
Upvotes: 15
Reputation: 4043
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.
Upvotes: -2