Send progress data from a Flask server to the browser client using emit and multiprocessing/multithreading

43 views Asked by At

I have a Flask app that, basically, searches the web for URLs, passes chunks of those URLs to a worker(url, **kwargs) function that elaborates on each url, and finally renders a results.html template. I want to add a progress indicator in my index.html template, which is used to input some variables that are passed to the webSearch(parameters) function.

This is the scheme of my app:

    import all the required modules, included multiprocessing Pool, Manager, etc
    from flask_socketio import SocketIO, emit
    ...
    ...

setting some helper functions:

    def webSearch(parameters):
    ...

    def func1(parameters):
    ...

    def func2(parameters):
    ...
    

instantiating the app:

    app = Flask(__name__)
    socketio = SocketIO(app, namespace="/progress")
    

defining my worker() function (which is really complex, so I'll just specify a few lines:

    def worker(url, number_of_urls_to_be_passed, done_list, **kwargs):
        done_list.append(url) #done_list is a list of the urls that have been passed to worker()
        progress = len(done_list) / number_of_urls_to_be_passed * 100
        socketio.emit('progress', {'progress': progress}, namespace='/progress')
        #here the function completes its task

now, I set the remaining part of my app:

    @app.route("/", methods=["GET", "POST"])
    def index():
        #get some input values (keywords, etc) from the index.html template
        def run():
            urls = webSearch(parameters)

            manager = Manager()
            done_list = manager.list()
            p = Pool(os.cpu_count())    
            mapfunc = partial(worker, done_list, **kwargs)   
            p.map(mapfunc, set(urls))

naively, I expected the socketio.emit call defined inside the worker() function to append each elaborated-on url to done_list (which happens) and to emit the progress value to the client.

my basic client javascript:

        <script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
        <script>
        var socket = io.connect('http://' + document.domain + ':' + location.port + '/progress');
        socket.on('progress', function (data) {
        document.getElementById('progress').style.width = data.progress + '%';
        document.getElementById('progress').innerHTML = data.progress + '%';
            });
        </script>
            

finally:

    if __name__ == "__main__":
        socketio.run(app, debug=True, host="0.0.0.0", port="5000")

This set up does not work as no 'progress' value is sent to the client and the field I have in my index.html template is not populated with any ongoing value. No signal detected in the Console as well.

I understand this is not working due to the multiprocessing environment. I tried with multithreading as well and did not succeed.

0

There are 0 answers