Reputation: 359
I'm trying to call a blocking function through a Flask method but it take several second, so I was thinking I could do some async call to speed things up but it doesn't work as expected. Apparently with asyncio I can't just launch a coroutine in background and don't wait for the end of the execution, maybe I need to use thread? Or use grequest as my blocking function is using request...
Here's my code so far:
@app.route("/ressource", methods=["GET"])
def get_ressource():
do_stuff()
return make_response("OK",200)
def do_stuff():
# Some stuff
fetch_ressource()
async def fetch_ressource():
return await blocking_function()
def blocking_function():
# Take 2-3 seconds
result = request.get('path/to/remote/ressource')
put_in_database(result)
I heard about Celeri but it seems a little overkill for only one function.
Upvotes: 11
Views: 27696
Reputation: 440
It's a little bit late to answer, but I am interested in this.
I manage it by wrapping the function and calling it via asyncio.run()
, but I don't know if multiple asyncio.run()
calls is a good thing to do.
from functools import wraps
from flask import Flask
import asyncio
def async_action(f):
@wraps(f)
def wrapped(*args, **kwargs):
return asyncio.run(f(*args, **kwargs))
return wrapped
app = Flask(__name__)
@app.route('/')
@async_action
async def index():
await asyncio.sleep(2)
return 'Hello world !'
app.run()
Upvotes: 5
Reputation: 5122
Consider using Sanic framework, its designed with asynchronous operations in mind, and you can see the sanic version of the code here
Upvotes: 0
Reputation: 7039
You can do this with Quart and AIOHTTP with code that should be very familiar to the Flask code given,
@app.route("/ressource", methods=["POST"])
async def get_ressource():
asyncio.ensure_future(blocking_function())
return await make_response("OK", 202)
async def blocking_function():
async with aiohttp.ClientSession() as session:
async with session.get('path/to/remote/ressource') as resp:
result = await resp.text()
await put_in_database(result)
Note: I've changed it to a POST route as it does something and I've returned a 202 response to indicate that it has triggered processing.
Should you wish to stick with Flask I recommend you use eventlet and use spawn(blocking_function)
without the async
or await
inclusions.
Also Note I am the Quart author.
Upvotes: 6
Reputation: 8589
What is the blocking function doing?
Could be using grequests feasible?
import grequests
@app.route('/do', methods = ['POST'])
def do():
result = grequests.map([grequests.get('slow api')])
return result[0].content
Upvotes: 0