Files

67 lines
3.0 KiB
Markdown

[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)