Skip to content
Bluetape4k docs1.11

Near Cache architecture and regions

Latest stable Based on Bluetape4k release 1.11.0

Each LettuceNearCache combines a process-local Caffeine L1 with a shared Redis L2. Reads check L1 first and populate it from Redis on a miss. Writes update Redis before populating L1.

Hibernate SessionFactory
└─ LettuceNearCacheRegionFactory
├─ entity region ─ Caffeine L1 + Redis L2
├─ collection region ─ Caffeine L1 + Redis L2
└─ query region ─ Caffeine L1 + Redis L2

If Redis SET fails, LettuceNearCache.put throws before changing L1. StorageAccess logs and absorbs that failure, allowing the database transaction to continue without completing the cache put.

LettuceNearCacheRegionFactory uses ConcurrentHashMap.computeIfAbsent, so repeated storage-access requests for a region share one Redis connection and Caffeine cache.

val nearCache = caches.computeIfAbsent(regionName) {
LettuceNearCache(client, codec, properties.buildNearCacheConfig(regionName))
}

getCaches() exposes an unmodifiable view for Metrics and Actuator. Application code cannot bypass factory ownership by adding or removing entries.

Near Cache prefixes Redis keys with {regionName}:. StorageAccess first converts the Hibernate key to hck2:<SHA-256 digest>, producing keys such as:

io.example.Product:hck2:K3...digest

Region eviction scans ${regionName}:* and uses UNLINK; it never uses FLUSHDB, so other region prefixes remain intact.

The persistence context in a Hibernate Session is the first-level cache. Two finds in one Session do not prove that the Lettuce second-level cache is working.

repeat(2) {
sessionFactory.openSession().use { session ->
session.beginTransaction()
checkNotNull(session.find(Product::class.java, id))
session.transaction.commit()
}
}

Use new Sessions and inspect secondLevelCacheHitCount.