Cache Configuration Guide¶
WBORM provides a powerful and flexible caching system for query results, supporting multiple storage backends, configurable TTL, and detailed statistics.
Table of Contents¶
- Quick Start
- Global Configuration
- Per-Query Configuration
- Cache Backends
- Cache Statistics
- Cache Invalidation
- Advanced Usage
Quick Start¶
By default, WBORM caches query results for 60 seconds using an in-memory backend:
from wbjdbc import connect_to_db
from wborm import generate_model
conn = connect_to_db(...)
Cliente = generate_model("clientes", conn)
# First call - queries database
clientes = Cliente.filter(status="ATIVO").all()
# Second call (within 60s) - uses cache
clientes = Cliente.filter(status="ATIVO").all() # Cached!
Global Configuration¶
Change Cache TTL¶
from wborm import configure_cache
# Set TTL to 5 minutes
configure_cache(ttl=300)
# Disable TTL (cache never expires)
configure_cache(ttl=None)
Disable Caching Globally¶
from wborm import configure_cache
# Disable all caching
configure_cache(enabled=False)
# Re-enable caching
configure_cache(enabled=True)
Set Maximum Cache Size¶
from wborm import configure_cache
# Limit cache to 100 entries (oldest evicted when full)
configure_cache(max_size=100)
Per-Query Configuration¶
Bypass Cache with .live()¶
# Force fresh query (ignore cache)
clientes = Cliente.filter(status="ATIVO").live().all()
Custom TTL per Query¶
# Cache this query for 10 minutes
clientes = Cliente.filter(status="ATIVO").cache(ttl=600).all()
Disable Cache for Specific Query¶
# Equivalent to .live()
clientes = Cliente.filter(status="ATIVO").cache(enabled=False).all()
Cache Backends¶
WBORM supports multiple cache storage backends:
1. Memory Cache (Default)¶
Simple dictionary-based in-memory cache:
from wborm import configure_cache, MemoryCacheBackend
# Unlimited size
configure_cache(backend=MemoryCacheBackend())
# With max size (oldest evicted)
configure_cache(backend=MemoryCacheBackend(max_size=500))
Pros: - Fast access - Simple
Cons: - Lost on process restart - No LRU eviction
2. LRU Cache¶
Least Recently Used cache with smart eviction:
from wborm import configure_cache, LRUCacheBackend
# LRU cache with 100 entries
configure_cache(backend=LRUCacheBackend(max_size=100))
Pros: - Keeps frequently accessed queries - Automatic eviction of unused entries
Cons: - Lost on process restart - Slightly slower than memory cache
3. Disk Cache¶
Persistent file-based cache:
from wborm import configure_cache, DiskCacheBackend
# Use system temp directory
configure_cache(backend=DiskCacheBackend())
# Custom cache directory
configure_cache(backend=DiskCacheBackend(
cache_dir="/var/cache/wborm",
max_size=1000
))
Pros: - Persists across restarts - Can handle very large caches
Cons: - Slower than memory cache - Requires disk I/O
Cache Statistics¶
Track cache performance with built-in statistics:
from wborm import cache_stats
# Get statistics
stats = cache_stats()
print(f"Cache Hits: {stats['hits']}")
print(f"Cache Misses: {stats['misses']}")
print(f"Hit Rate: {stats['hit_rate']:.1%}")
print(f"Cache Size: {stats['size']} entries")
print(f"Total Sets: {stats['sets']}")
print(f"Invalidations: {stats['invalidations']}")
Example output:
Cache Hits: 1,234
Cache Misses: 156
Hit Rate: 88.8%
Cache Size: 42 entries
Total Sets: 156
Invalidations: 12
Reset Statistics¶
from wborm import get_cache_config
config = get_cache_config()
config.reset_stats()
Cache Invalidation¶
Clear All Cache¶
from wborm import clear_cache
# Remove all cached queries
clear_cache()
Invalidate Specific Query¶
from wborm import invalidate_cache
# Invalidate by SQL pattern
invalidate_cache("SELECT * FROM clientes WHERE status = 'ATIVO'")
Manual Invalidation¶
from wborm import get_cache_config
config = get_cache_config()
# Invalidate specific cache key
cache_key = "your_cache_key_here"
config.invalidate(cache_key)
Advanced Usage¶
Custom Cache Configuration Object¶
from wborm import CacheConfig, LRUCacheBackend
# Create custom configuration
custom_config = CacheConfig(
enabled=True,
ttl=300, # 5 minutes
backend=LRUCacheBackend(max_size=200),
stats_enabled=True
)
# Use in QuerySet (requires internal access)
# This is typically done internally by WBORM
Conditional Caching¶
import os
# Disable cache in development
if os.getenv("ENV") == "development":
configure_cache(enabled=False)
else:
configure_cache(enabled=True, ttl=600)
Cache Warming¶
# Pre-populate cache with common queries
def warm_cache():
Cliente.filter(status="ATIVO").all()
Cliente.filter(tipo="VIP").all()
Pedido.filter(data_criacao__gt="2024-01-01").all()
# Call on application startup
warm_cache()
Monitoring Cache Performance¶
import time
from wborm import cache_stats
def monitor_cache():
while True:
stats = cache_stats()
if stats['hit_rate'] < 0.7: # Below 70%
print(f"⚠️ Low cache hit rate: {stats['hit_rate']:.1%}")
time.sleep(60) # Check every minute
Dynamic TTL Based on Query Complexity¶
def smart_cache_ttl(queryset):
"""Adjust TTL based on query complexity"""
if queryset._joins:
# Complex queries with joins: cache longer
return queryset.cache(ttl=600) # 10 minutes
else:
# Simple queries: cache shorter
return queryset.cache(ttl=60) # 1 minute
# Usage
clientes = smart_cache_ttl(Cliente.filter(status="ATIVO")).all()
Best Practices¶
1. Choose the Right Backend¶
- Development: Memory cache (simple, fast)
- Production with restarts: Disk cache (persistent)
- High-traffic APIs: LRU cache (smart eviction)
2. Set Appropriate TTL¶
# Fast-changing data: short TTL
configure_cache(ttl=30) # 30 seconds
# Reference data: long TTL
configure_cache(ttl=3600) # 1 hour
# Static data: no expiration
configure_cache(ttl=None)
3. Use .live() for Critical Queries¶
# Always get fresh data for financial calculations
saldo = Conta.filter(id=conta_id).live().sum("saldo")
4. Monitor Cache Statistics¶
# Periodically check cache performance
stats = cache_stats()
if stats['hit_rate'] < 0.5:
print("Consider increasing cache size or TTL")
5. Clear Cache After Bulk Operations¶
# After bulk insert/update/delete
Cliente.bulk_update(...)
clear_cache() # Invalidate all cached queries
Examples¶
Example 1: Production Configuration¶
from wborm import configure_cache, LRUCacheBackend
# LRU cache with 5-minute TTL
configure_cache(
enabled=True,
ttl=300,
backend=LRUCacheBackend(max_size=500)
)
Example 2: Development Configuration¶
from wborm import configure_cache
# Short TTL for development
configure_cache(
enabled=True,
ttl=10, # 10 seconds only
max_size=50
)
Example 3: Persistent Cache¶
from wborm import configure_cache, DiskCacheBackend
# Disk cache for microservices (survives restarts)
configure_cache(
backend=DiskCacheBackend(
cache_dir="/app/cache",
max_size=1000
),
ttl=600
)
Example 4: Mixed Caching Strategy¶
# Global configuration with moderate TTL
configure_cache(ttl=120)
# Critical queries: always fresh
saldo = Conta.live().sum("saldo")
# Heavy queries: cache longer
relatorio = (
Vendas.select("categoria", "COUNT(*)", "SUM(valor)")
.group_by("categoria")
.cache(ttl=1800) # 30 minutes
.all()
)
# Real-time data: no cache
usuarios_online = Usuario.filter(online=True).live().count()
Migration from Old Cache System¶
If you're upgrading from WBORM < 0.4.0, the cache system now uses the new configuration:
Old (deprecated):
# TTL was hardcoded to 60 seconds
# Cache used global _query_result_cache dict
New:
from wborm import configure_cache
# Explicit configuration
configure_cache(ttl=60) # Same as before
# Or customize
configure_cache(ttl=300, backend=LRUCacheBackend(100))
All existing code continues to work - the new system is backward compatible.
API Reference¶
configure_cache(enabled=None, ttl=None, backend=None, max_size=None, stats_enabled=None)¶
Configure global cache settings.
Parameters:
- enabled (bool): Enable/disable caching globally
- ttl (int): Time-to-live in seconds (None = no expiration)
- backend (CacheBackend): Cache storage backend instance
- max_size (int): Maximum cache entries (for MemoryCacheBackend)
- stats_enabled (bool): Enable statistics tracking
clear_cache()¶
Clear all cached query results.
cache_stats()¶
Get cache statistics dictionary.
Returns:
{
'hits': int,
'misses': int,
'hit_rate': float,
'size': int,
'sets': int,
'evictions': int,
'invalidations': int
}
invalidate_cache(pattern=None)¶
Invalidate cache entries matching pattern.
Parameters:
- pattern (str, optional): SQL pattern to match (None = clear all)
Returns: Number of entries invalidated
get_cache_config()¶
Get global cache configuration object.
Returns: CacheConfig instance
Troubleshooting¶
Cache Not Working¶
from wborm import get_cache_config
config = get_cache_config()
print(f"Cache enabled: {config.enabled}")
print(f"Cache TTL: {config.ttl}")
Low Hit Rate¶
- Increase
max_sizeif evictions are high - Increase
ttlif misses are high - Consider using
LRUCacheBackend
Memory Usage Too High¶
- Reduce
max_size - Use
LRUCacheBackendwith smaller size - Switch to
DiskCacheBackend
Note: Cache configuration is global per Python process. If using multiple processes (e.g., Gunicorn workers), each process has its own cache.