3

I'v created a Flask-SocketIO python server that should log data from a socket.io JavaScript client.

Server:

from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
socketio = SocketIO(app)

@socketio.on('connect')
def handle_connect():
    print 'Connected'

@socketio.on('disconnect')
def handle_disconnect():
    print 'Disconnected'

@socketio.on('start')
def handle_start():
    print 'Start'

@socketio.on('log')
def handle_log(data):
    print('Log: ' + data) 

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

Client:

<script src="socket.io.js"></script>

<script>
    function sleep(ms) {
        var unixtime_ms = new Date().getTime();
        while(new Date().getTime() < unixtime_ms + ms) {}
    }

    var socket = io.connect('http://127.0.0.1:5000', {'forceNew':true });
    socket.on('connect', function()
    {
        socket.emit('start');
        socket.emit('log', '1');
        socket.emit('log', '2');
        socket.emit('log', '3'); 

        sleep(3000)
    });
</script>

Instead of seeing the server printing "Start", "Log: 1", "Log: 2" and "Log: 3" immediately.

The server only prints "Start" and after 3 seconds prints all the other messages in one shot.

This is a problem as I require realtime logging, and cannot afford receiving all the logs in one shot at the end of execution.

Any idea why this is happening and what is the correct way to implement this simple log server?

3
  • 2
    Does it work if you comment out the sleep(3000) call? Commented Oct 31, 2017 at 0:51
  • It works because the function ends, and only when the function ends do all the other emit gets fired. I need the other emits to happen at real time, and not only when the function ends. Commented Oct 31, 2017 at 10:30
  • 1
    The fact that the function ends is irrelevant. The key here is that you are blocking when you call sleep(). You can't block, as JS is an asynchronous language. Commented Oct 31, 2017 at 16:37

1 Answer 1

2

The sleep() function that you are using is really bad for JavaScript, as you aren't really sleeping but busy-waiting. That means that the CPU is engaged during those 3 seconds, so other tasks that need CPU to run get delayed.

If you need to wait 3 seconds before doing something else, I suggest you use a timer object:

window.setTimeout(function() { alert('do something!'); }, 3000);

If you sleep using a timeout you will be releasing the CPU during the wait time, and that allows the JS scheduler to give it to other tasks that need it, such as those that support the Socket.IO emits.

Hope this helps!

Sign up to request clarification or add additional context in comments.

7 Comments

This is unrelated to my question, the point is that the first emit ("Start") happens immediately (in real time), and the other emits are for some reason "stuck" until the function ends. Only when the function ends do all the other emits occur.
Thanks for the downvote. You don't seem to be familiar with how asynchronous systems work, so I suggest you read on that to understand why your sleep() function is indeed the problem.
I appreciate your help, but using sleep was just an example to simplify my question. My original code has "window.location.reload()" instead of sleep. Because the emit calls don't happen immediately (they are async), the reload process and the emits call are in a race condition and some emits successfully call the server but some are missed because the page has been reload. From what I'v seen emit is buffering requests (1-n) and flushing them only in certain times (end of function for example). I need a way to ensure the emit is flushed, hence my question and using sleep as a simplification.
@Michael sorry to keep bringing bad news to you, but you can't force stuff to happen synchronously in JavaScript. It's not a bug, that's how things work by design. The fact that one of your emits got through and the other three did not is just a coincidence. On another machine maybe none get thorugh before the sleep call, and on another maybe two or three get through before you block on the sleep. There's nothing you can do about that. What you can do however, is design your application properly to work with asynchronous calls.
If you want to emit a bunch of things and then call reload, just attach a callback to your last emit, and do the reload when that emit completes and the callback is invoked.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.