Cache (Redis)
CacheService in commons provides a Lettuce-backed Redis client with async-first operations.
Configuration
redis:
host: "localhost"
port: 6379
password: "" # leave blank if Redis AUTH is disabled
database: 0
API Overview
All methods return CompletableFuture<T>. The service uses a shared Lettuce connection with 3 I/O threads.
String Operations
CacheService cache = AstralCore.get().cache();
// Set with optional TTL
cache.set("key", "value");
cache.set("session:abc", "data", Duration.ofMinutes(30));
// Get
cache.get("key").thenAccept(val -> System.out.println(val));
// Delete
cache.del("key");
// Check existence
cache.exists("key").thenAccept(exists -> { });
// Set expiry
cache.expire("key", Duration.ofHours(1));
Hash Operations
// Set a field
cache.hset("player:uuid", "kills", "42");
// Get a field
cache.hget("player:uuid", "kills");
// Get all fields
cache.hgetall("player:uuid").thenAccept(map -> { });
// Delete fields
cache.hdel("player:uuid", "kills", "deaths");
// Field count
cache.hlen("player:uuid");
// Check field existence
cache.hexists("player:uuid", "kills");
// All values
cache.hvals("player:uuid");
List Operations
cache.lpush("queue:tasks", "task1", "task2");
cache.lpop("queue:tasks");
cache.lrange("queue:tasks", 0, -1); // all elements
cache.llen("queue:tasks");
cache.lrem("queue:tasks", 1, "task1");
Set Operations
cache.sadd("online:players", uuid.toString());
cache.srem("online:players", uuid.toString());
cache.smembers("online:players");
cache.sismember("online:players", uuid.toString());
Pattern Keys
cache.keys("player:*").thenAccept(keys -> { });
Direct Commands
For operations not wrapped by convenience methods, use the raw async command interface:
cache.runAsync(commands ->
commands.incrby("counter", 5)
).thenAccept(newValue -> { });
CacheRepository
CacheRepository<T> provides a typed, JSON-serialised cache layer for domain objects implementing Unique:
public class PlayerCacheRepository extends CacheRepository<MinecraftPlayer> {
public PlayerCacheRepository(CacheService cache) {
super(cache, MinecraftPlayer.class, "player", Duration.ofMinutes(10));
}
}
Method | Description |
|---|
findById(UUID)
| Fetch by unique ID |
findByIds(Collection<UUID>)
| Batch fetch |
findByKey(String)
| Fetch by custom key |
findByPattern(String)
| Pattern-based scan |
findAll()
| All cached entities |
set(T)
| Cache with default TTL |
set(T, Duration)
| Cache with custom TTL |
set(String, T, Duration)
| Cache under custom key |
delete(UUID)
| Remove by ID |
deleteByPattern(String)
| Pattern delete |
exists(UUID)
| Existence check |
Object serialisation uses Jackson with Adventure Component support.
Distributed Locks
// Acquire a lock with default TTL (30 seconds)
DistributedLock lock = cache.lock("payment:player123");
// With custom TTL
DistributedLock lock = cache.lock("payment:player123", Duration.ofSeconds(10));
// Non-blocking try
if (lock.tryLock()) {
try {
// critical section
} finally {
lock.unlock();
}
}
// Blocking with timeout
if (lock.tryLock(Duration.ofSeconds(5))) {
try {
// critical section
} finally {
lock.unlock();
}
}
// Auto-release wrapper
lock.executeWithLock(() -> {
// critical section — lock is released automatically
});
Locks use Redis SET NX with Lua scripts for atomic extension and release. Lock keys follow the format lock:<key>.
Thread Pool
Lettuce uses 3 I/O event loop threads (named via Netty). The default is 2 × CPU cores; the reduced size prevents unnecessary thread creation on busy servers.
Cache load | Recommended threads |
|---|
Light | 2 |
Medium (default) | 3 |
Heavy | 4–5 |
Configured in commons/src/main/java/com/astralrealms/core/cache/LettuceDataSource.java:17 as EVENT_LOOP_THREADS.
23 April 2026