When using Spring Cache with Redis, we observed a potential issue with @CacheEvict(allEntries=true) in combination with @CachePut that leads to intermittent deletion of newly inserted keys.
Environment:
- Spring Boot: 4.0.6
- Redis: 8.6.2
- Redis: single node, TTL=-1 for all keys, non-clustered, single instance
- CacheWriter: default non-locking RedisCacheWriter
- Method visibility: public
@CachePut return values are never null
- No transactions involved (
@Transactional removed)
Steps to Reproduce:
- Define an empty
@CacheEvict method on a cacheName:
@CacheEvict(cacheNames = "xxx", allEntries = true)
public void clearCache() {}
- Call
clearCache() and then insert multiple items using @CachePut:
clearCache();
putCache(item1);
putCache(item2);
- Use
redis-cli MONITOR to track commands.
Observed Behavior:
- With
beforeInvocation=false (default), the command sequence may be:
keys cacheName::*
set cacheName::item1 ...
unlink keys_from_snapshot
set cacheName::item2 ...
-
The UNLINK command may asynchronously delete the newly inserted first item, causing it to disappear.
-
This behavior occurs intermittently.
-
When beforeInvocation=true, the command sequence becomes:
keys cacheName::*
del keys_from_snapshot
set cacheName::item1 ...
set cacheName::item2 ...
- In this case, all newly inserted items are preserved.
Questions:
- Why are the values of
beforeInvocation being changed using two different instructions, namely DEL and UNLINK??
- Mechanically speaking, how exactly does UNLINK get inserted into the middle of the SET command for execution?
- Is this behavior documented or expected, and should beforeInvocation=true be recommended whenever using allEntries=true with Redis and non-locking CacheWriter?
When using Spring Cache with Redis, we observed a potential issue with
@CacheEvict(allEntries=true)in combination with@CachePutthat leads to intermittent deletion of newly inserted keys.Environment:
@CachePutreturn values are never null@Transactionalremoved)Steps to Reproduce:
@CacheEvictmethod on a cacheName:clearCache()and then insert multiple items using@CachePut:redis-cli MONITORto track commands.Observed Behavior:
beforeInvocation=false(default), the command sequence may be:The
UNLINKcommand may asynchronously delete the newly inserted first item, causing it to disappear.This behavior occurs intermittently.
When
beforeInvocation=true, the command sequence becomes:Questions:
beforeInvocationbeing changed using two different instructions, namely DEL and UNLINK??