Flask App: Update progress bar while function runs

As some others suggested in the comments, the simplest solution is to run your exporting function in another thread, and let your client pull progress information with another request.
There are multiple approaches to handle this particular task.
Depending on your needs, you might opt for a more or less sophisticated one.

Here’s a very (very) minimal example on how to do it with threads:

import random
import threading
import time

from flask import Flask


class ExportingThread(threading.Thread):
    def __init__(self):
        self.progress = 0
        super().__init__()

    def run(self):
        # Your exporting stuff goes here ...
        for _ in range(10):
            time.sleep(1)
            self.progress += 10


exporting_threads = {}
app = Flask(__name__)
app.debug = True


@app.route("https://stackoverflow.com/")
def index():
    global exporting_threads

    thread_id = random.randint(0, 10000)
    exporting_threads[thread_id] = ExportingThread()
    exporting_threads[thread_id].start()

    return 'task id: #%s' % thread_id


@app.route('/progress/<int:thread_id>')
def progress(thread_id):
    global exporting_threads

    return str(exporting_threads[thread_id].progress)


if __name__ == '__main__':
    app.run()

In the index route (/) we spawn a thread for each exporting task, and we return an ID to that task so that the client can retrieve it later with the progress route (/progress/[exporting_thread]).
The exporting thread updates its progress value every time it thinks it is appropriate.

On the client side, you would get something like this (this example uses jQuery):

function check_progress(task_id, progress_bar) {
    function worker() {
        $.get('progress/' + task_id, function(data) {
            if (progress < 100) {
                progress_bar.set_progress(progress)
                setTimeout(worker, 1000)
            }
        })
    }
}

As said, this example is very minimalistic and you should probably go for a slightly more sophisticated approach.
Usually, we would store the progress of a particular thread in a database or a cache of some sort, so that we don’t rely on a shared structure, hence avoiding most of the memory and concurrency issues my example has.

Redis (https://redis.io) is an in-memory database store that is generally well-suited for this kind of tasks.
It integrates ver nicely with Python (https://pypi.python.org/pypi/redis).

Leave a Comment