The long story short is that Flask does not provide any special capabilities to accomplish this. For simple one-off tasks, consider Python's multithreading as shown below. For more complex configurations, use a task queue like RQ or Celery.

Why?

It's important to understand the functions Flask provides and why they do not accomplish the intended goal. All of these are useful in other cases and are good reading, but don't help with background tasks.

Flask's after_request handler

Flask's after_request handler, as detailed in this pattern for deferred request callbacks and this snippet on attaching different functions per request, will pass the request to the callback function. The intended use case is to modify the request, such as to attach a cookie.

Thus the request will wait around for these handlers to finish executing because the expectation is that the request itself will change as a result.

Flask's teardown_request handler

This is similar to after_request, but teardown_request doesn't receive the request object. So that means it won't wait for the request, right?

This seems like the solution, as this answer to a similar Stack Overflow question suggests. And since Flask's documentation explains that teardown callbacks are independent of the actual request and do not receive the request context, you'd have good reason to believe this.

Unfortunately, teardown_request is still synchronous, it just happens at a later part of Flask's request handling when the request is no longer modifiable. Flask will still wait for teardown functions to complete before returning the response, as this list of Flask callbacks and errors dictates.

Flask's streaming responses

Flask can stream responses by passing a generator to Response(), as this Stack Overflow answer to a similar question suggests.

With streaming, the client does begin receiving the response before the request concludes. However, the request still runs synchronously, so the worker handling the request is busy until the stream is finished.

This Flask pattern for streaming includes some documentation on using stream_with_context(), which is necessary to include the request context.

So what's the solution?

Flask doesn't offer a solution to run functions in the background because this isn't Flask's responsibility.

In most cases, the best way to solve this problem is to use a task queue such as RQ or Celery. These manage tricky things like configuration, scheduling, and distributing workers for you.This is the most common answer to this type of question because it is the most correct, and forces you to set things up in a way where you consider context, etc. correctly.

If you need to run a function in the background and don't want to set up a queue to manage this, you can use Python's built in threading or multiprocessing to spawn a background worker.

You can't access request or others of Flask's thread locals from background tasks, since the request will not be active there. Instead, pass the data you need from the view to the background thread when you create it.

@app.route('/start_task')
def start_task():
    def do_work(value):
        # do something that takes a long time
        import time
        time.sleep(value)

    thread = Thread(target=do_work, kwargs={'value': request.args.get('value', 20)})
    thread.start()
    return 'started'
Answer from Brandon Wang on Stack Overflow
Top answer
1 of 10
147

The long story short is that Flask does not provide any special capabilities to accomplish this. For simple one-off tasks, consider Python's multithreading as shown below. For more complex configurations, use a task queue like RQ or Celery.

Why?

It's important to understand the functions Flask provides and why they do not accomplish the intended goal. All of these are useful in other cases and are good reading, but don't help with background tasks.

Flask's after_request handler

Flask's after_request handler, as detailed in this pattern for deferred request callbacks and this snippet on attaching different functions per request, will pass the request to the callback function. The intended use case is to modify the request, such as to attach a cookie.

Thus the request will wait around for these handlers to finish executing because the expectation is that the request itself will change as a result.

Flask's teardown_request handler

This is similar to after_request, but teardown_request doesn't receive the request object. So that means it won't wait for the request, right?

This seems like the solution, as this answer to a similar Stack Overflow question suggests. And since Flask's documentation explains that teardown callbacks are independent of the actual request and do not receive the request context, you'd have good reason to believe this.

Unfortunately, teardown_request is still synchronous, it just happens at a later part of Flask's request handling when the request is no longer modifiable. Flask will still wait for teardown functions to complete before returning the response, as this list of Flask callbacks and errors dictates.

Flask's streaming responses

Flask can stream responses by passing a generator to Response(), as this Stack Overflow answer to a similar question suggests.

With streaming, the client does begin receiving the response before the request concludes. However, the request still runs synchronously, so the worker handling the request is busy until the stream is finished.

This Flask pattern for streaming includes some documentation on using stream_with_context(), which is necessary to include the request context.

So what's the solution?

Flask doesn't offer a solution to run functions in the background because this isn't Flask's responsibility.

In most cases, the best way to solve this problem is to use a task queue such as RQ or Celery. These manage tricky things like configuration, scheduling, and distributing workers for you.This is the most common answer to this type of question because it is the most correct, and forces you to set things up in a way where you consider context, etc. correctly.

If you need to run a function in the background and don't want to set up a queue to manage this, you can use Python's built in threading or multiprocessing to spawn a background worker.

You can't access request or others of Flask's thread locals from background tasks, since the request will not be active there. Instead, pass the data you need from the view to the background thread when you create it.

@app.route('/start_task')
def start_task():
    def do_work(value):
        # do something that takes a long time
        import time
        time.sleep(value)

    thread = Thread(target=do_work, kwargs={'value': request.args.get('value', 20)})
    thread.start()
    return 'started'
2 of 10
50

Flask is a WSGI app and as a result it fundamentally cannot handle anything after the response. This is why no such handler exists, the WSGI app itself is responsible only for constructing the response iterator object to the WSGI server.

A WSGI server however (like gunicorn) can very easily provide this functionality, but tying the application to the server is a very bad idea for a number of reasons.

For this exact reason, WSGI provides a spec for Middleware, and Werkzeug provides a number of helpers to simplify common Middleware functionality. Among them is a ClosingIterator class which allows you to hook methods up to the close method of the response iterator which is executed after the request is closed.

Here's an example of a naive after_response implementation done as a Flask extension:

import traceback
from werkzeug.wsgi import ClosingIterator

class AfterResponse:
    def __init__(self, app=None):
        self.callbacks = []
        if app:
            self.init_app(app)

    def __call__(self, callback):
        self.callbacks.append(callback)
        return callback

    def init_app(self, app):
        # install extension
        app.after_response = self

        # install middleware
        app.wsgi_app = AfterResponseMiddleware(app.wsgi_app, self)

    def flush(self):
        for fn in self.callbacks:
            try:
                fn()
            except Exception:
                traceback.print_exc()

class AfterResponseMiddleware:
    def __init__(self, application, after_response_ext):
        self.application = application
        self.after_response_ext = after_response_ext

    def __call__(self, environ, after_response):
        iterator = self.application(environ, after_response)
        try:
            return ClosingIterator(iterator, [self.after_response_ext.flush])
        except Exception:
            traceback.print_exc()
            return iterator

You can use this extension like this:

import flask
app = flask.Flask("after_response")
AfterResponse(app)

@app.after_response
def say_hi():
    print("hi")

@app.route("/")
def home():
    return "Success!\n"

When you curl "/" you'll see the following in your logs:

127.0.0.1 - - [24/Jun/2018 19:30:48] "GET / HTTP/1.1" 200 -
hi

This solves the issue simply without introducing either threads (GIL??) or having to install and manage a task queue and client software.

🌐
Beautiful Soup
tedboy.github.io › flask › werk_doc.tutorial.html
1. Werkzeug Tutorial — Flask API
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) return ['Hello World!']
🌐
Flask
flask.palletsprojects.com › en › stable › quickstart
Quickstart — Flask Documentation (3.1.x)
Such tuples have to be in the form (response, status), (response, headers), or (response, status, headers). The status value will override the status code and headers can be a list or dictionary of additional header values. If none of that works, Flask will assume the return value is a valid WSGI application and convert that into a response object.
🌐
Beautiful Soup
tedboy.github.io › flask › generated › generated › flask.Response.from_app.html
flask.Response.from_app — Flask API
flask.Response.from_app · View page source · Response.from_app(app, environ, buffered=False)¶ · Create a new response object from an application output. This works best if you pass it an application that returns a generator all the time. Sometimes applications may use the write() callable ...
🌐
Miguel Grinberg
blog.miguelgrinberg.com › post › customizing-the-flask-response-class
Customizing the Flask Response Class - miguelgrinberg.com
November 9, 2015 - Flask's application instance has a make_response() function, which takes the return value from the route function (which can be a single value or a tuple with one, two or three values) and populates a Response object with them.
Top answer
1 of 6
22

I will expose my solution.

You can use threads to compute anything after returned something in your function called by a flask route.

import time
from threading import Thread
from flask import request, Flask
app = Flask(__name__)


class Compute(Thread):
    def __init__(self, request):
        Thread.__init__(self)
        self.request = request

    def run(self):
        print("start")
        time.sleep(5)
        print(self.request)
        print("done")


@app.route('/myfunc', methods=["GET", "POST"])
def myfunc():
        thread_a = Compute(request.__copy__())
        thread_a.start()
        return "Processing in background", 200
2 of 6
16

You can try use streaming. See next example:

import time
from flask import Flask, Response

app = Flask(__name__)

@app.route('/')
def main():
    return '''<div>start</div>
    <script>
        var xhr = new XMLHttpRequest();
        xhr.open('GET', '/test', true);
        xhr.onreadystatechange = function(e) {
            var div = document.createElement('div');
            div.innerHTML = '' + this.readyState + ':' + this.responseText;
            document.body.appendChild(div);
        };
        xhr.send();
    </script>
    '''

@app.route('/test')
def test():
    def generate():
        app.logger.info('request started')
        for i in range(5):
            time.sleep(1)
            yield str(i)
        app.logger.info('request finished')
        yield ''
    return Response(generate(), mimetype='text/plain')

if __name__ == '__main__':
    app.run('0.0.0.0', 8080, True)

All magic in this example in genarator where you can start response data, after do some staff and yield empty data to end your stream.

For ditails look at http://flask.pocoo.org/docs/patterns/streaming/.

Find elsewhere
🌐
GitHub
github.com › miguelgrinberg › flask-sock › issues › 27
Try catching "AssertionError: write() before start_response" exception in a Flask application · Issue #27 · miguelgrinberg/flask-sock
May 10, 2022 - For instance, when restarted or closed, the information displayed in the local webpage is cleaned, and I have to recover it from the Python program via a notification or any signal. Currently I have a method for sending the data back to frontend via flask-sock, but since the Python program does not know when to act, the method is never executed.
Author   miguelgrinberg
🌐
Snyk
snyk.io › advisor › flask › functions › flask.response
How to use the flask.Response function in Flask | Snyk
Expects Method: POST Data: payload, puppyscript_name, data Optional Data: referrer, url """ response = Response() if request.method == 'POST': try: app.logger.info("request.form.get('payload', 0): {}".format( request.form.get('payload', 0))) puppyscript_name = urllib.unquote( unicode(request.form.get('puppyscript_name', ''))) # If they don't set a url or referrer, ignore it url = urllib.unquote(unicode(request.form.get('uri', ''))) referrer = urllib.unquote( unicode(request.form.get('referrer', ''))) try: if app.config.get('ALLOWED_DOMAINS'):
🌐
Beautiful Soup
tedboy.github.io › flask › generated › flask.make_response.html
flask.make_response — Flask API
if more than one argument is passed, the arguments are passed to the flask.Flask.make_response() function as tuple.
🌐
Beautiful Soup
tedboy.github.io › flask › generated › generated › flask.Response.html
flask.Response — Flask API
The response object that is used by default in Flask. Works like the response object from Werkzeug but is set to have an HTML mimetype by default.
🌐
GitHub
github.com › Parkayun › flask-responses
GitHub - Parkayun/flask-responses: Simple response utility for Flask.
from flask import Flask from flask.ext.responses import json_response, xml_response, auto_response app = Flask(__name__) @app.route("/json") def hello(): return json_response({"message": "Hello World!"}, status_code=201) @app.route("/xml") def world(): # or can do this return xml_response('<message>Hello World</message>') return xml_response({"message": "Hello World!"}, headers={'x-foo': 'bar'}) @app.route("/auto") def auto(): # auto response json or xml by Accept request header return auto_response({"message": "Hello World!"}, status_code=201, headers={'x-foo': 'bar'})
Starred by 14 users
Forked by 5 users
Languages   Python 100.0% | Python 100.0%
🌐
OverIQ
overiq.com › flask-101 › custom-response-and-hook-points-in-flask
Custom Response and Hook Points in Flask - Flask tutorial - OverIQ.com
Note that if the function registered by before_request decorator returns a response then the request handler will not be called. The following listing demonstrates how to utilize hooks points in Flask. Create a new file named hooks.py with the code as shown below: ... Start the server and make your first request by visiting http://localhost:5000/. In the standard output of the shell that runs the server you should get following output:
🌐
Readthedocs
flask-ask.readthedocs.io › en › latest › responses.html
Building Responses — Flask-Ask documentation
The two primary constructs in Flask-Ask for creating responses are statement and question. Statements terminate Echo sessions. The user is free to start another session, but Alexa will have no memory of it (unless persistence is programmed separately on the server with a database or the like).
🌐
Flask
flask.palletsprojects.com › api
API — Flask Documentation (3.1.x)
February 21, 2022 - Plain def functions are returned as-is. async def functions are wrapped to run and wait for the response. Override this method to change how the app runs async views. ... Added in version 2.0. ... Return a sync function that will run the coroutine function. ... Override this method to change how the app converts async code to be synchronously callable. ... Added in version 2.0. ... Generate a URL to the given endpoint with the given values. This is called by flask.url_for(), and can be called directly as well.
🌐
Flask
flask.palletsprojects.com › en › stable › errorhandling
Handling Application Errors — Flask Documentation (3.1.x)
from flask import json from werkzeug.exceptions import HTTPException @app.errorhandler(HTTPException) def handle_exception(e): """Return JSON instead of HTML for HTTP errors.""" # start with the correct headers and status code from the error response = e.get_response() # replace the body with JSON response.data = json.dumps({ "code": e.code, "name": e.name, "description": e.description, }) response.content_type = "application/json" return response
🌐
Flask
flask.palletsprojects.com › en › stable › patterns › appdispatch
Application Dispatching — Flask Documentation (3.1.x)
from threading import Lock class SubdomainDispatcher: def __init__(self, domain, create_app): self.domain = domain self.create_app = create_app self.lock = Lock() self.instances = {} def get_application(self, host): host = host.split(':')[0] assert host.endswith(self.domain), 'Configuration error' subdomain = host[:-len(self.domain)].rstrip('.') with self.lock: app = self.instances.get(subdomain) if app is None: app = self.create_app(subdomain) self.instances[subdomain] = app return app def __call__(self, environ, start_response): app = self.get_application(environ['HTTP_HOST']) return app(environ, start_response)
🌐
Plotly
community.plotly.com › dash python
Flask TypeError after updating to Python 3.10 - Dash Python - Plotly Community Forum
July 31, 2023 - I am using Dash on top of Flask and after upgrading to Python 3.10 I get the following TypeError when loading the main app in my browser: Traceback (most recent call last): File "[PATH_TO_VIRTUALENV]/lib/python3.10/site-packages/flask/app.py", line 2213, in __call__ return self.wsgi_app(environ, start_response) File "[PATH_TO_VIRTUALENV]/lib/python3.10/site-packages/flask/app.py", line 2193, in wsgi_app response = self.handle_exception(e) File "[PATH_TO_VIRTUALENV]/lib/python3.10/...
🌐
TestDriven.io
testdriven.io › blog › how-are-requests-processed-in-flask
How Are Requests Processed in Flask? | TestDriven.io
January 4, 2024 - In this case, the view function returns a “Hello World” response. Now let's investigate the key steps that happen before and after a view function is executed... This diagram illustrates the key steps that occur before and after a view function is executed: This diagram has a lot of steps, so I'll be walking through this sequence to show what occurs in each step. This sequence of steps is important to know when developing a Flask application, as it gives you insight into how Flask works to prepare for executing a view function and how the response is generated.