Publish / Subscribe
The included RedisPubSubService uses Redis' SUBSCRIBE/PUBLISH commands to provide a messaging service, which allows threads to communicate across JVM instances.
It multiplexes many (thousands of) threads/clients and their (virtual) channels onto a single channel on Redis. This is more scalable than letting each thread/client start its own dedicated subscription-connection to Redis.
It can for example be used to distribute events among JVMs/nodes and route those to their respective WebSocket sessions.
Things to be aware of:
- Delivery is at-most-once: messages published while a node is disconnected are lost.
- Each subscription buffers its incoming messages and handles them in order on its own virtual thread. Message order is preserved per publisher, not across publishers.
- If the message handler is too slow and the buffer (
messageBufferLimit, default10) is full, new messages are dropped and a warning is logged. - By default, a subscription also receives the messages it publishes itself (see
echoSelfbelow). - Messages are held in memory (
ByteArray) and shared between subscribers, so do not modify them in a handler.
Set up a shared RedisPubSubService
// share this as a bean/singleton. It handles re-connect upon failures internally.
val redisPubSubService = RedisPubSubService(
connectionPool = connectionPool,
).apply { start() } // waits until subscribed on Redis (up to connectTimeoutMs of the pool by default)
// on shutdown
redisPubSubService.stop()
Optional parameters:
| Parameter | Default | Description |
|---|---|---|
redisChannelName |
the class name | The channel used on Redis. Services which shall communicate must use the same name. |
delayBetweenReconnectMs |
1000 (milliseconds) |
Delay before reconnecting after a connection failure. |
heartbeatIntervalMs |
15000 (milliseconds) |
If nothing is received for this long, a PING is sent. If no reply arrives within another interval, the connection is considered dead and re-established. |
Start listening for messages/events
Start listening on the channels "foo" and "bar":
val subscription = redisPubSubService.subscribe(listOf("foo", "bar")) { channel: String, msg: ByteArray ->
println("$channel: ${msg.toString(redisStringCharset)}")
}
Send messages
Send a message to the channel "foo":
The message is delivered to all subscriptions of these channels, on all JVMs. Pass echoSelf = false to
not deliver it to the publishing subscription itself. A subscription created with an empty channel list
can be used for publishing only.