Flask is a single thread web server. But I want to make it won't block when handle some time consuming request.
For example:
from flask import Flask
import time
import sys
app = Flask(__name__)
#app.route("/")
def hello():
print "request"
sys.stdout.flush()
for _ in range(10000000):
for j in range(10000000):
i = 1
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
I want when every client request to server, it always output "request" on console immediately. I have try gunicorn and run with gunicorn -k gevent -w 4 a:app but it still appears synchronous.
This snippet is a good starting point.
You also should look into Celery or RQ, they're the right thing to use for larger projects, more importantly they're not Flask-specific.
They also have Flask integration each, Flask-Celery and Flask-RQ.
I believe you are asking about something called "streaming". For Flask this can be accomplished using generator functions and the yield keyword.
Streaming is covered in more detail in the official Flask documentation, have a look here.
Related
Setup :
Language i am using is Python
I am running a flask app with threaded =True and inside the flask app when an endpoint is hit, it starts a thread and returns a thread started successfully with status code 200.
Inside the thread, there is re.Search happening, which takes 30-40 seconds(worst case) and once the thread is completed it hits a callback URL completing one request.
Ideally, the Flask app is able to handle concurrent requests
Issue:
When the re.search is happening inside the thread, the flask app is not accepting concurrent requests. I am assuming some kind of thread locking is happening and unable to figure out.
Question :
is it ok to do threading(using multi processing) inside flask app which has "threaded = True"?
When regex is happening does it do any thread locking?
Code snippet: hit_callback does a post request to another api which is not needed for this issue.
import threading
from flask import *
import re
app = Flask(__name__)
#app.route(/text)
def temp():
text = request.json["text"]
def extract_company(text)
attrib_list = ["llc","ltd"] # realone is 700 in length
entity_attrib = r"((\s|^)" + r"(.)?(\s|$)|(\s|^)".join(attrib_list) + r"(\s|$))"
raw_client = re.search("(.*(?:" + entity_attrib + "))", text, re.I)
hit_callback(raw_client)
extract_thread = threading.Thread(target=extract_company, )
extract_thread.start()
return jsonify({"Response": True}), 200
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=4557, threaded=True)
Please read up on the GIL - basically, Python can only execute ONE piece of code at the same time - even if in threads. So your re-search runs and blocks all other threads until run to completion.
Solutions: Use Gunicorn etc. pp to run multiple flask processes - do not attempt to do everything in one flask process.
To add something: Also your design is problematic - 40 seconds or so for a http answer is way to long. A better design would have at least two services: a web server and a search service. The first would register a search and give back an id. Your search service would communicate asynchronously with the web service and return resullt +id when the result is ready. Your clients could pull the web service until they get a result.
I have a web endpoint for users to upload file.
When the endpoint receives the request, I want to run a background job to process the file.
Since the job would take time to complete, I wish to return the job_id to the user to track the status of the request while the job is running in background.
I am wondering if asyncio would help in this case.
import asyncio
#asyncio.coroutine
def process_file(job_id, file_obj):
<process the file and dump results in db>
#app.route('/file-upload', methods=['POST'])
def upload_file():
job_id = uuid()
process_file(job_id, requests.files['file']) . # I want this call to be asyc without any await
return jsonify('message' : 'Request received. Track the status using: " + `job_id`)
With the above code, process_file method is never called. Not able to understand why.
I am not sure if this is the right way to do it though, please help if I am missing something.
Flask doesn't support async calls yet.
To create and execute heavy tasks in background you can use https://flask.palletsprojects.com/en/1.1.x/patterns/celery/ Celery library.
You can use this for reference:
Making an asynchronous task in Flask
Official documentation:
http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html#installing-celery
Even though you wrote #asyncio.coroutine() around a function it is never awaited which tells a function to return result.
Asyncio is not good for such kind of tasks, because they are blocking I/O. It is usually used to make function calls and return results fast.
As #py_dude mentioned, Flask does not support async calls. If you are looking for a library that functions and feels similar to Flask but is asynchronous, I recommend checking out Sanic. Here is some sample code:
from sanic import Sanic
from sanic.response import json
app = Sanic()
#app.route("/")
async def test(request):
return json({"hello": "world"})
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
Updating your database asynchronously shouldn't be an issue; refer to here to find asyncio-supported database drivers. For processing your file, check out aiohttp. You can run your server extremely fast on a single thread without any hickup if you do so asynchronously.
I have a python script app.py in my local server (path=Users/soubhik.b/Desktop) that generates a report and mails it to certain receivers. Instead of scheduling this script on my localhost, i want to create an API which can be accessed by the receivers such that they would get the mail if they hit the API with say a certain id.
With the below code i can create an API to display a certain text. But, what do i modify to run the script through this?
Also if i want to place the script in a server instead of localhost, how do i configure the same?
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return ("hello world")
if __name__ == '__main__':
app.run(debug=True)
Python Version is 2.7
A good way to do this would be to put the script into a function, then import that function in your Flask API file and run it using that. For hosting on a web server you can use Python Anywhere if you are a beginner else heroku is also a good option.
If you are tying to achieve something using Python-Flask API than you can have a close look at this documentations and proceed further https://www.flaskapi.org/, http://flask.pocoo.org/docs/1.0/api/
Apart from these here are few basic examples and references you can refer for a quickstart :
1-https://programminghistorian.org/en/lessons/creating-apis-with-python-and-flask
2- https://flask-restful.readthedocs.io/en/latest/
3- https://realpython.com/flask-connexion-rest-api/
You could do something like this
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class ExecuteScript:
def printScript:
return "Hello World"
api.add_resource(ExecuteScript, '/printScript')
if __name__ == '__main__':
app.run(debug=True)
I am running a flask app using celery to offload long running process on a IIS 6.5 server and using python 2.7
The choice of the python 2.7, flask and IIS 7 server are imposed by the Company and cannot be changed.
The flask app works on IIS server (so the server set-up should be correct), except for the following.
I am struggling to find the good implementation to make flask works smoothly on the server.
I searched for similar questions on the site, but none helped so far.
When I am running the flask app on my pc, the application only performs as expected if I use OPTION A or OPTION B.
OPTION A:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello from FastCGI via IIS!"
if __name__ == "__main__":
app.run(threaded=True) # <--- This works
OPTION B:
If I wrap the flask app inside tornado, it works well as well:
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from myapp import app
http_server = HTTPServer(WSGIContainer(app))
http_server.listen(5000)
IOLoop.instance().start()
OPTION C:
However if I run the flask app only with the default parameters, then it does not work the webserver is not returning the view that should be returned after a task has been offloaded to celery.
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello from FastCGI via IIS!"
if __name__ == "__main__":
app.run() # <--- Default App
Example of view working for OPTION A & B but not for OPTION C or on ISS:
Here below a stripped down example of a async task that is picked by celery. Note that I'm using Flask-Classy to generate the views, so the code is slightly different than the traditional routing in Flask.
class AnalysisView(FlaskView):
### Index page ---------------
def index(self):
return render_template('analysis.intro.html')
### Calculation process ------
def calculate(self, run_id):
t_id = task_create_id(run_id)
current_analysis = a_celery_function.apply_async(args=[x, y], task_id=t_id)
# Redirect to another view --> Not working when OPTION C or on ISS server
return redirect(url_for('AnalysisView:inprogress', run_id=run_id))
### Waiting page ---------------
def inprogress(self, run_id=run_id):
return render_template('analysis.inprogress.html')
My main problem is how can I use OPTION A (preferably, as it involves less change for me) or OPTION B to work together with IIS server?
Is there a way to tell flask to run with threaded=True during the Flask() initialization or via config settings?
Thanks in advance for you help.
I am not able to successfully use Python Requests to call a second route in the same application using Flask. I know that its best practice to call the function directly, but I need it to call using the URL using requests. For example:
from flask import Flask
import requests
app = Flask(__name__)
#app.route("/")
def hello():
return "Hello World!" # This works
#app.route("/myrequest")
def myrequest():
#r = requests.get('http://www.stackoverflow.com', timeout=5).text # This works, but is external
#r = hello() # This works, but need requests to work
r = requests.get('http://127.0.0.1:5000/', timeout=5).text # This does NOT work - requests.exceptions.Timeout
return r
if __name__ == "__main__":
app.run(debug=True, port=5000)
Your code assumes that your app can handle multiple requests at once: the initial request, plus the request that is generated while the initial is being handled.
If you are running the development server like app.run(), it runs in a single thread by default; therefore, it can only handle one request at a time.
Use app.run(threaded=True) to enable multiple threads in the development server.
As of Flask 1.0 the development server is threaded by default.