Flask-socketio: Emitting from background thread to the second room blocks the first room

Created on 22 Nov 2018  路  19Comments  路  Source: miguelgrinberg/Flask-SocketIO

Hello dear Miguel
changes in app.py

```python3
i = 0

def background_thread():
"""Example of how to send server generated events to clients."""
#count = 0
global i
while True:
socketio.sleep(10)
#count += 1
socketio.emit('my_response',
{'data': 'Server generated event', 'count': count},
namespace='/test' , room = i)

@socketio.on('connect', namespace='/test')
def test_connect():
global thread
global i
i += 1
join_room(i)
with thread_lock:
if thread is None:
thread = socketio.start_background_task(target=background_thread)
emit('my_response', {'data': 'Connected', 'count': 0})
````

These are the only changes in you example code , client A connects and automatically gets his room and the background thread keeps emitting to his room , when B connects it get the thread event but it blocks thread generated event to A and so on .. C blocks B ...

question

Most helpful comment

If this is a robust application that you are building (i.e. not a quick test) you will need to keep track of those threads and stop them when their respective clients disconnect. The return value from the start_background_task function is the thread object, which you can store in a dictionary or similar data structure.

If you want to learn more about how green threads work, I recommend an excellent talk by Dave Beazley titled "concurrency from the ground up". It's on youtube.

All 19 comments

I think that this is a conflicting issue between eventlet and threading

I want to emit the background thread to each individual room

I think the confusion here is on your part. There is one one thread, you are not starting a different thread for each client. But even if you were, each thread would be sending events to the room stored in the i global variable, so all your threads would then be sending events to the last client. My code is not the right starting point for what you want to do, I'm afraid.

Yes , that is right . I commented

         # if thread is None:

what it did it just doubled the thread flow the the latest client .

So , do i need to evade global room variable ?

Yes, pass the room as an argument to your thread.

Adding args gives and error

```python3

roo = ["a","b" , "c","d"]
i =0
def background_thread(j):
"""Example of how to send server generated events to clients."""
# count = 0
print(roo[j])
while True:
socketio.sleep(3)
# count += 1
socketio.emit('my_response',
{'data': 'Thread generated event', 'count': roo[j]},
namespace='/test' , room= roo[j]) # emit to the room

@socketio.on('connect', namespace='/test')
def test_connect():
global thread
global i
i += 1
print(roo[i])
join_room(roo[i]) # join to the newly created room automatically
with thread_lock:
# if thread is None:
thread = socketio.start_background_task(target=background_thread , args = (i,) )
print(thread)
emit('my_response', {'data': 'Connected', 'count': 0})
````
dd

Do it like this:

thread = socketio.start_background_task(background_thread, i)

Thank you ! at long last i get the solution , now it works fine

It is great to join newly connected client to his individual room on-fly and direct a separate background thread strictly to him simultaneously with other events .

I wonder how does this work , both threading and eventlet do their asynchronous jobs , say , Green threads , i want to know how i can track their zeroes and ones , i mean monitoring and controlling them up to their roots ..

Any way , thank you very much for solving world's problems

If this is a robust application that you are building (i.e. not a quick test) you will need to keep track of those threads and stop them when their respective clients disconnect. The return value from the start_background_task function is the thread object, which you can store in a dictionary or similar data structure.

If you want to learn more about how green threads work, I recommend an excellent talk by Dave Beazley titled "concurrency from the ground up". It's on youtube.

I have learnt python from Dave Beazley's vidoe courses . He taught me not only how to code but also what is like to be a coding expert .

Thank you for the recommendation

Now , i want to subclass background threads in SocketI O. Before doing this i want to take a look at the root code of socketio.start_background_task , where is it located ? i mean how did you right this from bare-bone Python code ?

The implementation is here: https://github.com/miguelgrinberg/python-engineio/blob/master/engineio/server.py#L332

Unfortunately you are not going to find straightforward code there, because starting a thread is different in regular Python vs eventlet vs gevent, so my solution is based on configuration variables that are set different for each of these, but in all cases there is a Thread class that creates the thread object, then you call start() on this object to start the background thread.

Ok , Thank you .

I want to start second independent function besides def background_thread(): , say def background_thread_2(): in a "single thread" object in Connection event , but the target gets just one function . Of course we can use second thread with synchronization with first one ,
any idea ?

That's not how threads work. If you need two independent lines of execution, then that's two threads, can't make it one. So you'll need to call start_background_task() for each background task.

Ok , thank you

Another issue ; Let's say that , we want to emit from thread to an app.route :


roo = ["a","b" , "c","d"]
i =0 
def background_thread(j):
    """Example of how to send server generated events to clients."""
    # count = 0   
    print(roo[j])
    while True:
        socketio.sleep(3)
        # count += 1
        socketio.emit('my_response',
                      {'data': 'Thread generated event', 'count': roo[j]},
                      namespace='/test' , room= roo[j])    # emit to the room


@socketio.on('connect', namespace='/test')
def test_connect():
    global thread
    global i
    i += 1
    print(roo[i])
    join_room(roo[i])   # join to the newly created room automatically
    with thread_lock:
         # if thread is None:
            thread = socketio.start_background_task(background_thread , i)
            print(thread)
    emit('my_response', {'data': 'Connected', 'count': 0})

@app.route('/show')
def ff():
       pass
````
how should we redirect the thread event 

```python3
socketio.emit('my_response',
                      {'data': 'Thread generated event', 'count': roo[j]},
                      namespace='/test' , room= roo[j])    # emit to the room

into the route

@app.route('/show')
def ff():
       pass

and how we should write def ff() ? to properly receive the my_response thread event ?

No, you seem to be trying to do something that this library doesn't do. Emits go to clients, not to other parts of the server. If you need your threads to pass data around, you need to use threading synchronization primitives and possibly also global variables.

Ok , thank you very much .

Is there a way to set the max number of workers with socketio.start_background_task? I believe I have seen it with thread or another concurrency library. If not what are your thoughts on setting up a queue as a work around?

@srianbury no, I think what you refer is a thread pool, which something more sophisticated than this function. You should look within the concurrency library that you are using to see what options for pools of workers they offer.

Okay will do!

p.s. I see you actively answer questions and issues and I very much appreciate it. I have resolved many problems by reading a lot of your comments.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thehelpfulbees picture thehelpfulbees  路  4Comments

huangganggui picture huangganggui  路  3Comments

zuifengwuchou picture zuifengwuchou  路  5Comments

benjaminturley picture benjaminturley  路  4Comments

nh916 picture nh916  路  3Comments