Add redis: Boot 4.1 + Spring Data Redis 4.1, the JDK-serialisation default vs Jackson 3 serializers, @RedisHash TTL and keyspace events, @RedisListener, and Redis as the Spring cache
Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
[Home](../README.md) | Prev: [Hash TTL and keyspace events](06-hash-ttl-and-keyspace-events.md) | Next: [TTL](08-ttl.md)
|
||||
|
||||
# 7. Pub/Sub
|
||||
|
||||
Redis Pub/Sub is a broadcast: `PUBLISH channel message` sends the message to whoever is subscribed
|
||||
to the channel *at that moment*, and Redis keeps nothing. The reply to `PUBLISH` is the number of
|
||||
subscribers that received it.
|
||||
|
||||
## Boot 4.1 sets up the receiving side
|
||||
|
||||
Older articles declare a `RedisMessageListenerContainer` bean by hand. Boot 4.1 registers one
|
||||
(`redisMessageListenerContainer`) and enables `@RedisListener`, so a listener is a method
|
||||
([NewsListener](../src/main/java/com/ankurm/redis/messaging/NewsListener.java)):
|
||||
|
||||
```java
|
||||
@RedisListener(topic = "news")
|
||||
void onNews(String body) { ... }
|
||||
```
|
||||
|
||||
[11-pub-sub.txt](output/11-pub-sub.txt) starts with what Boot did:
|
||||
|
||||
```
|
||||
beans of type RedisMessageListenerContainer: [redisMessageListenerContainer]
|
||||
running=true listening=true
|
||||
```
|
||||
|
||||
A topic that contains a glob (`alerts.*`) subscribes with `PSUBSCRIBE`; the channel the message came
|
||||
in on is available as a header (`@Header(PubSubHeaders.CHANNEL) String channel`). The
|
||||
`@RedisListener` attributes, from the jar, are `id`, `container`, `value`, `topic` and `consumes`.
|
||||
A `String` parameter receives the raw body; a `org.springframework.data.redis.connection.Message`
|
||||
parameter did not work in this test, because the adapter tried to parse the payload as JSON
|
||||
(a `StreamReadException` on the text `90% full`). This repository does not investigate why.
|
||||
|
||||
## Sending
|
||||
|
||||
`stringRedisTemplate.convertAndSend(channel, message)` returns the number of receivers:
|
||||
|
||||
- to a channel nobody listens to: `0`, and the message is gone;
|
||||
- to `news` with the annotation listener: `1`;
|
||||
- after a second listener is added to the same channel through the container, still `1`, because the container subscribes once to the channel and fans out to its listeners in-process. Both listeners received the message. The number is receivers on the Redis side, not listeners on yours.
|
||||
|
||||
`PUBSUB NUMSUB alerts.disk` is `0` while a pattern subscriber is receiving on `alerts.*`: `NUMSUB`
|
||||
counts channel subscribers only, and `PUBSUB NUMPAT` counts patterns. `PUBLISH` counts both.
|
||||
|
||||
## At-most-once
|
||||
|
||||
[12-pub-sub-lost-message.txt](output/12-pub-sub-lost-message.txt): stop the container, publish, start
|
||||
it again.
|
||||
|
||||
```
|
||||
template.convertAndSend("news", "while you were away") = 0 receivers
|
||||
...
|
||||
messages the listener has: []
|
||||
```
|
||||
|
||||
Nothing is queued. That is the design, and it is why Pub/Sub is right for cache invalidation hints and
|
||||
live dashboards, and wrong for anything that must not be lost. For that, look at Redis Streams
|
||||
(not covered in this repository).
|
||||
|
||||
## Going deeper
|
||||
|
||||
- [PubSubTest](../src/test/java/com/ankurm/redis/PubSubTest.java)
|
||||
- [Redis Pub/Sub](https://redis.io/docs/latest/develop/pubsub/)
|
||||
- [Spring Data Redis: Pub/Sub messaging](https://docs.spring.io/spring-data/redis/reference/redis/pubsub.html)
|
||||
|
||||
[Home](../README.md) | Prev: [Hash TTL and keyspace events](06-hash-ttl-and-keyspace-events.md) | Next: [TTL](08-ttl.md)
|
||||
Reference in New Issue
Block a user