Making an Asynchronous Task in Flask

Making an asynchronous task in Flask

I would use Celery to handle the asynchronous task for you. You'll need to install a broker to serve as your task queue (RabbitMQ and Redis are recommended).

app.py:

from flask import Flask
from celery import Celery

broker_url = 'amqp://guest@localhost' # Broker URL for RabbitMQ task queue

app = Flask(__name__)
celery = Celery(app.name, broker=broker_url)
celery.config_from_object('celeryconfig') # Your celery configurations in a celeryconfig.py

@celery.task(bind=True)
def some_long_task(self, x, y):
# Do some long task
...

@app.route('/render/<id>', methods=['POST'])
def render_script(id=None):
...
data = json.loads(request.data)
text_list = data.get('text_list')
final_file = audio_class.render_audio(data=text_list)
some_long_task.delay(x, y) # Call your async task and pass whatever necessary variables
return Response(
mimetype='application/json',
status=200
)

Run your Flask app, and start another process to run your celery worker.

$ celery worker -A app.celery --loglevel=debug

I would also refer to Miguel Gringberg's write up for a more in depth guide to using Celery with Flask.

Is there a way to make flask asynchronous

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.

Synchronous api tasks on Python Flask

First, depending on what you mean by "async", yes, you can make HTTP requests to a Flask app that arranges to do work asynchronously. That's what tasks queues like celery and Rq are for. There's a good walk-through of using Rq in chapter 22 of the Flask Mega Tutorial.

Second, if you only have a single process, single thread web server, then yes, requests are handled sequentially. In practice, though, you'll deploy behind something like uwsgi or gunicorn, which manage multiple processes running your app.

How to send asynchronous request using flask to an endpoint with small timeout session?

If you are trying to have a async task in request, you have to decide whether you want the result/progress or not.

  1. You don't care about the result of the task or if there where any errors while processing the task. You can just process this in a Thread and forget about the result.
  2. If you just want to know about success/fail for the task. You can store the state of the task in Database and query it when needed.
  3. If you want progress of the tasks like (20% done ... 40% done). You have to use something more sophisticated like celery, rabbitMQ.

For you i think option #2 fits better. You can create a simple table GitTasks.

  GitTasks
------------------------
Id(PK) | Status | Result
------------------------
1 |Processing| -
2 | Done | <your result>
3 | Error | <error details>

You have to create a simple Threaded object in python to processing.

 import threading  
class AsyncGitTask(threading.Thread):
def __init__(self, task_id, params):
self.task_id = task_id
self.params = params
def run():
## Do processing
## store the result in table for id = self.task_id

You have to create another endpoint to query the status of you task.

  @app.route('/TaskStatus/<int:task_id>')
def task_status(task_id):
## query GitTask table and accordingly return data

Now that we have build all the components we have to put them together in your main request.

  from Flask import url_for
@app.route('/', methods=['POST', 'GET'])
def handle_data():
.....
## create a new row in GitTasks table, and use its PK(id) as task_id
task_id = create_new_task_row()
async_task = AsyncGitTask(task_id=task_id, params=params)
async_task.start()

task_status_url = url_for('task_status', task_id=task_id)
## This is request you can return text saying
## that "Your task is being processed. To see the progress
## go to <task_status_url>"


Related Topics



Leave a reply



Submit