miguelgrinberg / Flask-SocketIO

Socket.IO integration for Flask applications.
MIT License
5.31k stars 888 forks source link

Sending events in a separate thread with delays does not send #2057

Closed Kalilamodow closed 2 months ago

Kalilamodow commented 2 months ago

Describe the bug I have a separate background thread which creates and sends events to the clients. However, whenever there is any blocking functions in it, the events don't send.

To Reproduce Let's say this is the file:

app = f.Flask(__name__)
socketio = fsio.SocketIO(app, logger=True, engineio_logger=True)

def background_task():
    while True:
        socketio.send("hello")

@app.route("/")
def index():
    return """
<h1>hi</h1>

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.5/socket.io.min.js" integrity="sha512-11t8Q+vY9JlCrr+PveZKTYJq8n7O09Y5X/pk/aMd3vJugSvu4xOunGEUzaADqL3I8cZKE/pBwwCfXzDkRJh2sQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const socketio = io();
socketio.on("connect", () => console.log("connected"));
socketio.onAny((...args) => console.log(...args));
</script>
"""

if __name__ == "__main__":
    bgtask = threading.Thread(target=background_task)
    bgtask.start()
    socketio.run(app, use_reloader=False, reloader_options={}, log_output=True)

As expected, it peppers the client's console with "hello". However, when I do this:

app = f.Flask(__name__)
socketio = fsio.SocketIO(app, logger=True, engineio_logger=True)

def background_task():
    while True:
        socketio.send("hello")
        time.sleep(1)

@app.route("/")
def index():
    return """
<h1>hi</h1>

<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.5/socket.io.min.js" integrity="sha512-11t8Q+vY9JlCrr+PveZKTYJq8n7O09Y5X/pk/aMd3vJugSvu4xOunGEUzaADqL3I8cZKE/pBwwCfXzDkRJh2sQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const socketio = io();
socketio.on("connect", () => console.log("connected"));
socketio.onAny((...args) => console.log(...args));
</script>
"""

if __name__ == "__main__":
    bgtask = threading.Thread(target=background_task)
    bgtask.start()
    socketio.run(app, use_reloader=False, reloader_options={}, log_output=True)

The client just doesn't seem to receive anything.

Logs The logs for both scenarios are the same - something like this

{conn id}: Upgrade to websocket successful
(84076) accepted ('127.0.0.1', 40623)
emitting event "message" to all [/]
Lh-iEwxI60LVc2QtAAAA: Sending packet MESSAGE data 2["message","hello"]
emitting event "message" to all [/]
Lh-iEwxI60LVc2QtAAAA: Sending packet MESSAGE data 2["message","hello"]
emitting event "message" to all [/]
Lh-iEwxI60LVc2QtAAAA: Sending packet MESSAGE data 2["message","hello"]
...
miguelgrinberg commented 2 months ago

If you are using gevent or eventlet, then this is expected. These frameworks suspend concurrency if you block. Use the sleep function provided by your framework of choice, or socketio.sleep().

And by the way, threads are also not well supported if you are using gevent or eventlet. Use socketio.start_background_task() instead.