scalatra
scalatra copied to clipboard
RedisScalatraBroadcaster's broadcast method blocks AtmosphereClient receive
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?
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).
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)
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?)