5

I want to emit a delayed message to a socket client. For example, when a new client connects, "checking is started" message should be emitted to the client, and after a certain seconds another message from a thread should be emitted.

@socket.on('doSomething', namespace='/test')
def onDoSomething(data):
  t = threading.Timer(4, checkSomeResources)
  t.start()
  emit('doingSomething', 'checking is started')

def checkSomeResources()
  # ...
  # some work which takes several seconds comes here
  # ...
  emit('doingSomething', 'checking is done')

But the code does not work because of context issue. I get

RuntimeError('working outside of request context')

Is it possible to make emitting from a thread?

Muatik
  • 4,011
  • 10
  • 39
  • 72

1 Answers1

4

The problem is that the thread does not have the context to know what user to address the message to.

You can pass request.namespace to the thread as an argument, and then send the message with it. Example:

@socket.on('doSomething', namespace='/test')
def onDoSomething(data):
    t = threading.Timer(4, checkSomeResources, request.namespace)
    t.start()
    emit('doingSomething', 'checking is started')

def checkSomeResources(namespace)
    # ...
    # some work which takes several seconds comes here
    # ...
    namespace.emit('doingSomething', 'checking is done')
Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152
  • I think this answer will still fail if you have long running threads. See my answer below. – Jordan Lapp Aug 26 '15 at 21:18
  • 1
    This did fail for me. request.namespace is a string, which does not have an emit method. I've tried socketio.emit('doingSomething', namespace=request.namespace), but that's not working with class based Namespace either. Still stuck! – Paul Brown Sep 07 '17 at 22:37
  • Note the date on this answer. This is valid for a very old version. See the example application on the Flask-SocketIO repository on GitHub for a more recent example. – Miguel Grinberg Sep 08 '17 at 00:27