Skip to content

Cache Backends

KacheController ships three cache backends and accepts any custom implementation of CacheClient.

Backend Class External dependency Persistence
Redis RedisCacheClient Lettuce Shared, survives restarts
In-memory InMemoryCacheClient None Process-local, lost on restart
SQLite SQLiteCacheClient sqlite-jdbc File-based, single-process

Choosing a backend

  • Redis — the right default for production: shared across instances, survives restarts, supports per-field TTL (Redis 7.4+), and cluster-ready.
  • In-memory — integration tests, local development, or single-process workloads where a Redis dependency is undesirable.
  • SQLite — persistent local cache for single-process services where Redis is unavailable (e.g. edge deployments).

Implementing your own

CacheClient is a small interface. All methods are suspend and hash-based, modelling the Redis hash data type.

interface CacheClient {
    suspend fun hget(key: String, field: String): String?
    suspend fun hset(key: String, field: String, value: String): Boolean
    suspend fun hset(key: String, entries: Map<String, String>): Long
    suspend fun hdel(key: String, vararg fields: String): Long
    suspend fun del(vararg keys: String): Long
    suspend fun exists(key: String): Boolean
    suspend fun hgetAll(key: String): Map<String, String>

    // optional — default implementations are no-ops
    suspend fun expire(key: String, ttl: Duration) {}
    suspend fun hexpire(key: String, ttl: Duration, vararg fields: String) {}
}

expire and hexpire are optional. The default no-op implementations degrade gracefully: TTL parameters passed to controller methods are silently ignored if the backend does not support them.