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,71 @@
|
||||
[Home](../README.md) | Prev: [@RedisHash](05-redis-hash.md) | Next: [Pub/Sub](07-pub-sub.md)
|
||||
|
||||
# 6. Hash TTL and keyspace events
|
||||
|
||||
`@RedisHash(value = "session", timeToLive = 2)` gives every saved [Session](../src/main/java/com/ankurm/redis/hash/Session.java)
|
||||
a two-second TTL. Redis will delete the hash when the time is up. The question is what happens to
|
||||
everything Spring Data Redis wrote *around* the hash: the id in the `session` set, the
|
||||
`session:user:ankur` index, the `session:s1:idx` bookkeeping set (see [chapter 5](05-redis-hash.md)).
|
||||
|
||||
## With Boot's defaults: nothing
|
||||
|
||||
Boot enables Redis repositories with `enableKeyspaceEvents = OFF`
|
||||
([16-serializers-javap.txt](output/16-serializers-javap.txt), "Defaults of @EnableRedisRepositories").
|
||||
Redis expires the hash and nobody tells the application
|
||||
([09-hash-ttl-events-off.txt](output/09-hash-ttl-events-off.txt)):
|
||||
|
||||
```
|
||||
$ redis-cli -p 6390 KEYS '*' | sort
|
||||
session
|
||||
session:s1:idx
|
||||
session:user:ankur
|
||||
$ redis-cli -p 6390 SMEMBERS session | sort
|
||||
s1
|
||||
...
|
||||
sessions.findById("s1") = Optional.empty
|
||||
sessions.count() = 1
|
||||
```
|
||||
|
||||
`findById` is right (there is no hash), `count()` is wrong (the id is still in the set), and
|
||||
`session:user:ankur` still lists an id that resolves to nothing. On a busy system this accumulates.
|
||||
|
||||
## With ON_STARTUP: cleanup
|
||||
|
||||
`@EnableRedisRepositories(enableKeyspaceEvents = ON_STARTUP)` changes three things
|
||||
([10-hash-ttl-events-on.txt](output/10-hash-ttl-events-on.txt), test config in
|
||||
[HashTtlEventsOnTest](../src/test/java/com/ankurm/redis/HashTtlEventsOnTest.java)):
|
||||
|
||||
1. **The server setting.** Redis only publishes expiry notifications if `notify-keyspace-events` is set. It is empty by default, and Spring Data Redis sets it at startup (the annotation's `keyspaceNotificationsConfigParameter` defaults to `Ex`; Redis reports it back as `xE`):
|
||||
|
||||
```
|
||||
$ redis-cli -p 6390 --no-raw CONFIG GET notify-keyspace-events
|
||||
1) "notify-keyspace-events"
|
||||
2) "xE"
|
||||
```
|
||||
|
||||
Some managed Redis services restrict `CONFIG SET`; this repository does not run against one, so check yours. The `EnableKeyspaceEvents` enum also has an `ON_DEMAND` value, which is not exercised here.
|
||||
|
||||
2. **A phantom key.** Once a hash has expired there is nothing left to read, so Spring Data Redis writes a copy, `session:s1:phantom`, that outlives the hash by five minutes (302 seconds for a 2-second TTL). When the expiry notification arrives, Spring reads the phantom copy, removes the index entries, and deletes the phantom.
|
||||
|
||||
3. **An application event.** `RedisKeyExpiredEvent` is published with the deleted entity as its value, so an `@EventListener` can react (audit, cleanup, notify):
|
||||
|
||||
```
|
||||
RedisKeyExpiredEvent: keyspace=session id=s1 value=Session[id=s1, user=ankur]
|
||||
```
|
||||
|
||||
After it, `DBSIZE` is 0 and `count()` is 0.
|
||||
|
||||
## The catch
|
||||
|
||||
The expiry notification is delivered over Pub/Sub, which is fire-and-forget: a subscriber that is
|
||||
not connected when the message is published never sees it ([chapter 7](07-pub-sub.md) shows that
|
||||
with a stopped listener). If your application is down when a session expires, or the connection
|
||||
drops, the cleanup for that entry is not guaranteed. This repository does not test a missed notification. If exactness matters, do not build correctness on keyspace events; run a periodic job.
|
||||
|
||||
## Going deeper
|
||||
|
||||
- [HashTtlEventsOffTest](../src/test/java/com/ankurm/redis/HashTtlEventsOffTest.java)
|
||||
- [Redis keyspace notifications](https://redis.io/docs/latest/develop/pubsub/keyspace-notifications/)
|
||||
- [Spring Data Redis: Expirations and Time To Live](https://docs.spring.io/spring-data/redis/reference/redis/redis-repositories/expirations.html)
|
||||
|
||||
[Home](../README.md) | Prev: [@RedisHash](05-redis-hash.md) | Next: [Pub/Sub](07-pub-sub.md)
|
||||
Reference in New Issue
Block a user