I am attempting to implement a chat using Redis publish/subscribe with Spring Data Redis.
I use the RedisTemplate to publish messages, shown below:
public class RedisPublisher {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void publish(ChannelTopic channelTopic, Object channelMessage) {
redisTemplate.convertAndSend(channelTopic.getTopic(), channelMessage);
}
}
And to receive messages I have a MessageListener as shown below:
public class RedisConsumer implements MessageListener {
MessageSerializer serializer = new MessageSerializer();
AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public void onMessage(Message message, byte[] pattern) {
Object obj = serializer.deserialize(message.getBody());
if(obj != null && obj instanceof RedisMessage) {
System.err.println("Received message(" + atomicInteger.incrementAndGet() + ") " + obj.toString());
}
}
Messages are published like so:
final ChannelTopic channelTopic=connectionManager.subscribe("topic");
new Thread(new Runnable() {
public void run() {
Thread.sleep(5000);
for (int i = 0; i < 10; i++) {
redisPublisher.publish(channelTopic, new RedisMessage(i + 1));
}
}
}).run();
However, the received messages appear to be delivered in wrong order:
Received message(1) message id: 3
Received message(2) message id: 2
Received message(3) message id: 1
Received message(4) message id: 4
Received message(5) message id: 5
Received message(6) message id: 6
Received message(7) message id: 7
Received message(8) message id: 8
Received message(9) message id: 9
Received message(10) message id: 10
Is it possible to send/receive messages synchronously using the RedisTemplate/MessageListener provided by Spring?
The current code-base is small and can be viewed at GitHub.
Redis PubSub is known to deliver the messages in order (guaranteed at least if you use one connection and trigger PUBLISH
. The PUBLISH
command returns the number of clients that were notified). The cause for the out-of-order is the way how Spring Data Redis dispatches the messages by default. The notification is handled on different threads and that's the reason. Thanks for the code, it helped me to quickly reproduce the behavior.
I can think of two possible strategies to address this issue:
You can however supply an executor that honors the order within RedisMessageListenerContainer
. Right now, any form of synchronization I'm thinking of, would harm performance.
Implement an own message listener on top of BinaryJedisPubSub
. You're in control over the messages and you can omit the executor issue.
HTH, Mark
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With