Cache

Obsidian provides a unified cache facade backed by a swappable driver. Two drivers are available out of the box: an in-memory store for development, and Redis for production. Configuration is handled via environment variables — no code changes required to switch.

Environment configuration
In-memory (default)
CACHE_DRIVER=memory
Redis
CACHE_DRIVER=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=secret
Store and retrieve
Cache.put("user:42", user, 60);  // Store for 60 seconds

User user = Cache.get("user:42"); // Retrieve

if (Cache.has("user:42")) { ... } // Check existence

Cache.forget("user:42");          // Remove
remember — cache-aside pattern

Returns the cached value if present. Otherwise runs the supplier, caches the result, and returns it.

List<Article> articles = Cache.remember(
    "articles:all",
    300,
    () -> articleRepository.findAll()
);
Batch operations
// Store multiple entries with a shared TTL
Map<String, Object> entries = new HashMap<>();
entries.put("user:1", alice);
entries.put("user:2", bob);
Cache.putAll(entries, 120);

// Retrieve multiple keys in order
List<User> users = Cache.getAll(List.of("user:1", "user:2"));
Custom driver
public class MyCacheDriver implements CacheDriver {

    @Override
    public void put(String key, Object value, int ttlSeconds) { ... }

    @Override
    public Object get(String key) { ... }

    // implement has(), forget(), putAll(), getAll()
}

// Register before the server starts
Cache.setDriver(new MyCacheDriver());
💡 Behaviour
  • getAll() preserves key order — null is returned for missing or expired entries
  • • Redis batch ops use Jedis pipelining — a single round-trip for any number of keys
  • remember() is not atomic — under concurrent load, the supplier may run more than once
  • • The InMemory driver evicts lazily on get() — no background sweep