Is there a way to make flask asynchronous - python

Is there a way to make flask asynchronous? For example I want flask to pause for one second for a user and then display some text. Is there any way to do this?

Flask is based WSGI which is an API standard for connecting Python Web frameworks to Web servers.
And WSGI is a synchronous and blocking API.
If you are using flask render_template, like this :
#app.route('/home', methods=['GET'])
def hello(name=None):
return render_template('hello.html', name=name)
You can add a time.sleep() to make if wait before rendering the template.
But this is not a good practice
import time
#app.route('/home', methods=['GET'])
def hello(name=None):
time.sleep(30) #wait 30seconds
return render_template('hello.html', name=name)
But if you want to use it with a frontend in javascript, you should handle it on the client side.
And if you want to know about async tasks on flask you can take a look on Celery and this post.

Related

Flask: Storing Socket-Connection variables without Cookies

I need to have 'variables and activity associated with each client' without using cookies. How and where can i store this variables? I am pretty new to flask and servers.
For now, I thought of using a python dictionary and storing sessionID-variable pairs like shown below.
I have a feeling that this is a stupid idea, but I can not think of an alternative :/.
Hope, you can help me.
import flask
app = Flask(__name__)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
enter code heresocketio = SocketIO(app)
cache = {}
#app.route('/')
def index():
return send_from_directory('static', "index.html")
#socketio.on('savePseudonym')
def sendKeepAlive():
cache[(request.sid,'pseudonym')]= pseudonym
cache[(request.sid,'time')]= time
if __name__ == "__main__":
socketio.run(app, debug=True)
You can use session, in more or less the same way you use it with Flask routes.
from flask import session
#socketio.on('savePseudonym')
def sendKeepAlive():
session['pseudonym'] = pseudonym
session['time'] = time
The only thing to keep in mind is that because Socket.IO sessions are not based on cookies, any changes you make to the session in a Socket.IO handler will not appear on the Flask session cookie. If you need to share the session between Flask routes and Socket.IO event handlers, then you can use a server-side session with the Flask-Session extension.

Python Flask - Asyncio asynchronous Question

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.

route flask from scheduled function

I have a Flask app, which is running a web-app to control an alarm. I use apscheduler to trigger a function triggerAlarm() and within that I want to have the logic to actually trigger it, but also I want to have the web-page to display another alarm.html, no matter which site the user is currently on.
The idea is to show the user, that the alarm went off by opening another html page (possibly the main page, which has context dependent text and layout)! Also the page content is outdated after an alarm. The client must reload the page, if the after-alarm info should be displayed/updated.
This is the key problem: in my head it is necessary to redirect every client to the alarm page at this event. Maybe there is a better solution all along. (I don't want to use JavaScript, since I use 4 languages already besides the 3 I use regularly.)
The problem is, that the function itself has no "route" and is not part of the app (this is what I think happens). Also I cannot easily make it a route, since it is activated not by a html request, but by the scheduler.
How can I trigger a function and redirect to a specified page?
*I tried redirect() and RequestRedirect() w/ and w/o url_for() and return render_template('index.html', **templateData) ... but I cannot load the desired page.
The code looks something like this:
from apscheduler.schedulers.background import BackgroundScheduler
# Web Server Gateway WSGI
from flask import Flask, render_template, request, url_for
scheduler = BackgroundScheduler()
scheduler.start()
scheduler.add_job(triggerAlarm,'date',run_date=somedate)
#app.route("/")
def index():
# prepare templateData
return render_template('index.html', **templateData)
def triggerAlarm():
# this doesn't work, since it is called by the scheduler and has no route!
return redirect(url_for("/"))
If you have defined a method, "triggerAlarm()", and want to make it available to a route, then create your route like:
#app.route("/alarm-url")
def web_alarm():
triggerAlarm()
return redirect(url_for("/"))
This will cause the same thing that happens when the scheduler runs triggerAlarm() to happen when a user hits the route /alarm-url, and then return them home.
The takeaway is that you can define methods outside of flask route, in other modules, etc, and then call those methods in a flask route.
Update
If you have to keep triggerAlarm() separate from any routes you could do something like:
class StatusDenied(Exception):
pass
#app.errorhandler(StatusDenied)
def web_alarm(error):
return redirect(url_for("/"))
def triggerAlarm():
...
raise StatusDenied

Setup custom request context with flask

I have a complex service that runs flask queries asynchronously. So the flask app accepts requests and submits them to a queue and returns a handle to the caller. Then an async service picks up these requests and runs them and then submits the response to a data-store. The caller would continuously poll the flask endpoint to check if the data is available. Currently, this asynchronous feature is only available for a single flask endpoint. But I want to extend this to multiple flask endpoints. As such, I am putting in the code that submits the request to the queue in a python decorator. So that this decorator can be applied to any flask endpoint and then it would support this asynchronous feature.
But to achieve this seamlessly, I have the need to setup a custom request context for flask. This is because the flask endpoints use request.args, request.json, jsonify from flask. And the async service just calls the functions associated with the flask endpoints.
I tried using app.test_request_context() but this doesn't allow me to assign to request.json.
with app.test_request_context() as req:
req.request.json = json.dump(args)
The above doesn't work and throws the below error
AttributeError: can't set attribute
How can I achieve this?
Answer is
builder = EnvironBuilder(path='/',
query_string=urllib.urlencode(query_options), method='POST', data=json.dumps(post_payload),
content_type="application/json")
env = builder.get_environ()
with app.request_context(env):
func_to_call(*args, **kwargs)

How to run flask request as asynchronous form with uwsgi?

I have one flask application 'merge.py'. From this I am calling two request and getting their response as:
from flask import Flask
from flask import request, jsonify
import json
import time
import requests
app = Flask(__name__)
#app.route('/check')
def check_working():
result_1 = requests.get('http://0.0.0.0:8080/hello').content
result_2 = requests.get('http://0.0.0.0:7000/bye').content
return "True"
if __name__=='__main__':
app.run(debug=True,host='128.7.7.10',threaded=True)
Right now when I am running the above file, both the request '/hello' and '/bye' running synchronously. How I can make them asynchronous with uwsgi. Suppose '/hello' is taking 10sec and '/bye' is taking 5sec, so total time it should take to execute is 10sec not 15sec. I want to collect the output of both the request. How I can achieve the asynchronous behavior here.
Thanks

Categories

Resources