Caching
The client stores downloaded definitions in memory and also retains evaluation results. These are separate layers: evaluating a flag is normally a local operation, not an API call per check.
How Caching Works
At initialization, the client downloads shared application/environment definitions. Later evaluations can use a retained decision or evaluate a loaded definition. Polling and optional live updates obtain new definitions; decision retention has its own TTL.
Configuration
Cache TTL
The default decision TTL is 60 seconds. Set cache_ttl(Duration::from_secs(...)) on the config or client builder. Do not treat TTL as an exact propagation-time guarantee, or assume that constructing a new EvalContext requests a fresh decision.
Maximum Cache Entries
The default capacity setting is 10,000. Capacity handling attempts expired-entry cleanup and batch eviction; it is not an oldest-first or LRU contract.
Cache Keys
Keep each operation's context owned by that operation. Supplying a context does not invalidate existing decisions. Choose refresh and retention behavior deliberately; context mapping describes the inputs used during evaluation.
Cache Invalidation
Manual Invalidation
Use these helpers with an initialized shared client:
use toggly::TogglyClient;
pub async fn refresh_definitions(client: &TogglyClient) -> toggly::Result<()> {
// Successful explicit refresh also clears retained decisions.
client.refresh().await
}
pub async fn clear_and_reload(client: &TogglyClient) -> toggly::Result<()> {
// This also removes in-memory definitions and signing-key state.
client.clear_cache().await;
client.refresh().await
}
Do not clear/reload on every incoming request. It discards shared definitions and adds avoidable network work. An application-owned refresh operation can be useful after an administrative configuration change.
Automatic Invalidation
Periodic polling updates definitions. Do not equate the arrival of a new definition revision with an immediate change in every already-cached decision. client.refresh() is the explicit client operation that clears decisions after its definition refresh succeeds.
Memory Management
The cache lives in process memory. There is no public client cache-statistics accessor or persisted evaluated-snapshot store. Do not access private client.cache or client.provider fields from application code.
Monitoring
use toggly::TogglyClient;
pub async fn diagnostics(client: &TogglyClient) {
println!("Definition ETag: {:?}", client.etag().await);
println!("Last refresh error: {:?}", client.last_error().await);
println!("Loaded keys: {}", client.feature_keys().await.len());
}
An ETag identifies definition state; it is not a cache-hit ratio or a user's evaluated flag snapshot. last_error is the last definition-refresh error, not a record of every evaluation.
Best Practices
Keep one client for the application's lifetime, prepare request context before evaluation, and avoid process-wide user mutation. Await close() after draining requests; close clears decisions and flushes enabled telemetry best-effort before signaling provider shutdown.
Signed Definitions and Live Updates
Signed definitions and optional WebSocket updates use the same client lifecycle. Signing verifies definition authenticity; it does not add a disk snapshot API or an atomic export of evaluated flags. Configure these mechanisms through TogglyConfig.