Bloke
Bloke

Reputation: 2469

How to wait for a callback passed to Flask-SocketIO's emit()?

Is there a way in Flask-SocketIO to have a blocking/synchronous emit('event', callback) function that waits for the callback passed to it before returning?

Or -- is there a way to directly invoke the callback in an @socketio.on('event') handler instead of the plain return from that handler?


This is my situation specifically:

+-----------------+                            +----------------------+                         +----------------------+
|     Browser     |  emit('serverGiveData',    |        Flask         |  emit('workerGiveData', |       Worker         |
|  (webapp, JS)   |       browser_callback)    |      web server      |       server_callback)  |   (Python program)   |
|                 | +------------------------> |                      | +-------------------->  |                      |
|                 |                            |                      |                         |                      |
| socket.io 1.7.3 |            data            | Flask-SocketIO 2.8.2 |          data           |socketiIO-client 0.7.2|
|                 | <------------------------+ |                      | <--------------------+  |                      |
|                 |                            |                      |                         |                      |
+-----------------+                            +----------------------+                         +----------------------+

So the Browser wants data from the Worker and the Flask web server is just a proxy in between.

I would like the browser_callback() to be invoked after the Server receives the data from the Worker.
(I.e. I would like to call the browser_callback() from the server_callback()).

However, I cannot invoke the browser_callback() from server_callback() manually in Flask-SocketIO -- it is "automatically" invoked when I return from 'serverGiveData' handler function on the Server. That is why I would like to have a blocking/synchronous emit('workerGiveData') so that the handler on the Server doesn't return before the Worker delivers the data.


Here's the code

Browser

socketio.emit('serverGiveData', args, function (data) {
    console.log('Received data');
});

Server

@socketio.on('serverGiveData')
def handler(msg):
    socketio.emit('workerGiveData', msg, callback=server_callback)
    return  # When server_callback() gets called back

def server_callback(data):
    print('Received data from Worker')
    # Here I want to invoke client_callback(), i.e.
    # I don't want handler() to return before this server_callback() is invoked

Worker

def handler(args, callback);
    callback(data)

socketIO.on('workerGiveData', handler)

(I am aware I could emit('heyBrowserHeresData') from the server_callback() when the Worker delivers the data and listen on that event in the browser with browser_callback() code as the handler.
I would like to avoid that jumble.)

Upvotes: 3

Views: 4822

Answers (1)

Miguel Grinberg
Miguel Grinberg

Reputation: 67509

The Socket.IO protocol is event-based, not request/response based. I recommend that you don't use the callbacks, those are for quick acknowledgement that an event was received, not to provide results after some work was done.

Try this instead to use a new event to replace your callback:

+-----------------+                            +----------------------+                         +----------------------+
|     Browser     |  emit('serverGiveData’)    |        Flask         |  emit('workerGiveData', |       Worker         |
|  (webapp, JS)   |                            |      web server      |       server_callback)  |   (Python program)   |
|                 | +------------------------> |                      | +-------------------->  |                      |
|                 |                            |                      |                         |                      |
| socket.io 1.7.3 |  emit(‘dataForBrowser’)    | Flask-SocketIO 2.8.2 |          data           |socketiIO-client 0.7.2|
|                 | <------------------------+ |                      | <--------------------+  |                      |
|                 |                            |                      |                         |                      |
+-----------------+                            +----------------------+                         +----------------------+

You can leave the second callback on the server-side if that works well for you, or less you can also replace it with an event.

Upvotes: 3

Related Questions