Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01B38FGKKam5SCGgwgduVAh3
3.7 KiB
Home | Prev: @RedisHash | Next: Pub/Sub
6. Hash TTL and keyspace events
@RedisHash(value = "session", timeToLive = 2) gives every saved Session
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).
With Boot's defaults: nothing
Boot enables Redis repositories with enableKeyspaceEvents = OFF
(16-serializers-javap.txt, "Defaults of @EnableRedisRepositories").
Redis expires the hash and nobody tells the application
(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, test config in
HashTtlEventsOnTest):
-
The server setting. Redis only publishes expiry notifications if
notify-keyspace-eventsis set. It is empty by default, and Spring Data Redis sets it at startup (the annotation'skeyspaceNotificationsConfigParameterdefaults toEx; Redis reports it back asxE):$ 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. TheEnableKeyspaceEventsenum also has anON_DEMANDvalue, which is not exercised here. -
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. -
An application event.
RedisKeyExpiredEventis published with the deleted entity as its value, so an@EventListenercan 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 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
Home | Prev: @RedisHash | Next: Pub/Sub