scalatra icon indicating copy to clipboard operation
scalatra copied to clipboard

RedisScalatraBroadcaster's broadcast method blocks AtmosphereClient receive

Open lloydmeta opened this issue 11 years ago • 3 comments

This is on 2.3.0-SNAPSHOT with changes in https://github.com/scalatra/scalatra/pull/365 (locally published)

Looks like when using RedisScalatraBroadcaster, using the broadcast method in an AtmosphereClient receive method causes the handling thread to become blocked and on subsequent pushes on the socket, that AtmosphereClient no longer does anything.

I created a quick app based on the chat sample and uploaded it here

If I put the broadcast in a Future { .. } block (see the above link), the handling thread is free and broadcasts to other windows, but on around the 5th - 6th try, broadcast no longer gets called, likely because the implicit ExecutionContext threads are all blocked. I was able to get more messages to go through by passing in a custom larger ExecutionContext into the Future.

Any thoughts?

lloydmeta avatar Feb 21 '14 12:02 lloydmeta

I should mention that using monitor from redis-cli, I can that see the messages are being PUBLISHed into redis even though the handler gets blocked (at least initially)

...
1392987075.826688 [0 127.0.0.1:55953] "PUBLISH" "/the-chat/*" "{\"msg\":\"{\\\"author\\\":\\\"hi\\\",\\\"message\\\":\\\"7254\\\",\\\"time\\\":\\\"1392987075825\\\"}\",\"clientFilter\":{\"jsonClass\":\"package$SkipSelf\",\"uuid\":\"31807fa3-e403-40c7-abf7-3b4c3e7cb669\"}}"
1392987076.554866 [0 127.0.0.1:55953] "PUBLISH" "/the-chat/*" "{\"msg\":\"{\\\"author\\\":\\\"hi\\\",\\\"message\\\":\\\"7123\\\",\\\"time\\\":\\\"1392987076553\\\"}\",\"clientFilter\":{\"jsonClass\":\"package$SkipSelf\",\"uuid\":\"31807fa3-e403-40c7-abf7-3b4c3e7cb669\"}}"
1392987103.321376 [0 127.0.0.1:55953] "PUBLISH" "/the-chat/*" "{\"msg\":\"{\\\"author\\\":\\\"hi\\\",\\\"message\\\":\\\"dsa\\\",\\\"time\\\":\\\"1392987103320\\\"}\",\"clientFilter\":{\"jsonClass\":\"package$SkipSelf\",\"uuid\":\"31807fa3-e403-40c7-abf7-3b4c3e7cb669\"}}"
...

At some point, this stops (sooner when using default ExecutionContext and later if using a custom one per AtmosphereClient with a huge thread pool).

lloydmeta avatar Feb 21 '14 13:02 lloydmeta

i got the same problem ! when i use 'RedisScalatraBroadcaster' instead of 'DefaultScalatraBroadcaster', i can see the messages are being published into redis, but the connections between clien and server are blocked. And the server can't sub message from redis success.

i debug the source code , the program block at this line :

  override def broadcast[T <: OutboundMessage](msg: T, clientFilter: ClientFilter)(implicit executionContext: ExecutionContext): Future[T] = {
    logger.info("Resource [%s] sending message to [%s] with contents:  [%s]".format(clientFilter.uuid, clientFilter, msg))
    // Casting to ProtocolMessage because when writing the message everything gets wrapped by a 'content' element.
    // This seems to be because the actual message is a ProtocolMessage which defines a 'content' method.
    val protocolMsg = msg.asInstanceOf[ProtocolMessage[Object]]
    val content = protocolMsg.content
    val actualMessage = write(content)
    val wrappedMessage = new Message(actualMessage, clientFilter)
    val wrappedMessageString = write(wrappedMessage)

    broadcast(wrappedMessageString).map(_ => msg)  // blocked at this line when return the broadcast result
  }

here is a temporary solution, write your own broadcaster and config class , use

 broadcast(wrappedMessageString)
 Future.successful[T](msg)

instead of

broadcast(wrappedMessageString).map(_ => msg)

linsheng9731 avatar Jul 14 '16 14:07 linsheng9731

thanks for this workaround. I just followed your example. Do you think it would be good to submit a patch? (which I'm happy to do?)

ludflu avatar Aug 29 '16 19:08 ludflu