Caching
The Java SDK supports caching to reduce API calls and improve performance.
Caffeine Cache
Caffeine provides high-performance in-memory caching, ideal for single-instance applications.
Installation
<dependency>
<groupId>io.toggly</groupId>
<artifactId>toggly-cache-caffeine</artifactId>
<version>1.5.1</version>
</dependency>
Configuration
SnapshotProvider httpProvider = new HttpSnapshotProvider(config);
SnapshotProvider cachedProvider = new CaffeineCachingSnapshotProvider(
httpProvider,
CaffeineCacheConfig.builder()
.expireAfterWrite(Duration.ofMinutes(5))
.refreshAfterWrite(Duration.ofMinutes(1))
.maximumSize(100)
.recordStats()
.build()
);
TogglyClient client = new TogglyClient(config, cachedProvider);
The examples assume an existing TogglyConfig config. Keep the client/provider
for the application's lifetime. Because the provider was supplied to the client,
close client first and cachedProvider second at shutdown; the outer cache closes
the HTTP delegate. HTTP polling/live updates do not evict this outer snapshot
cache, so its TTL/refresh policy can delay the definitions visible to evaluation.
Call the outer provider's refresh() to fetch through it explicitly.
Configuration Options
| Option | Default | Description |
|---|---|---|
expireAfterWrite | - | Time after which entries expire |
refreshAfterWrite | - | Time after which entries are refreshed asynchronously |
maximumSize | 0 (unlimited) | Maximum number of entries |
recordStats | false | Enable statistics recording |
Accessing Statistics
CaffeineCachingSnapshotProvider provider = ...;
CacheStats stats = provider.stats();
System.out.println("Hit rate: " + stats.hitRate());
System.out.println("Miss rate: " + stats.missRate());
System.out.println("Load count: " + stats.loadCount());
Evaluation Cache
Definition caching keeps evaluation sensitive to the current request context. Only add a result cache if stale answers are acceptable for its TTL. Its key uses the feature, identity and context hash (including claims/request/entity), but no definition revision or current time. A refresh or TimeWindow boundary therefore does not automatically invalidate an answer.
Use a short TTL and explicitly invalidate from application code when you know
definitions have changed. TogglyClient.onRefresh does not currently invoke
listeners; it cannot wire automatic invalidation. The following cache must be
long-lived, and every evaluation must pass the complete context:
CaffeineEvaluationCache evaluationCache = CaffeineEvaluationCache.builder()
.expireAfterWrite(Duration.ofSeconds(10))
.maximumSize(10000)
.recordStats()
.build();
// Use cached evaluation
boolean enabled = evaluationCache.getOrCompute(
"my-feature",
context,
() -> togglyClient.isEnabled("my-feature", context)
);
// Invalidate when features change
evaluationCache.invalidateFeature("my-feature");
evaluationCache.invalidateAll();
Redis Cache
Redis provides distributed caching, ideal for multi-instance deployments.
Installation
<dependency>
<groupId>io.toggly</groupId>
<artifactId>toggly-cache-redis</artifactId>
<version>1.5.1</version>
</dependency>