Skip to content

Caching

Provides various cache backends to reduce redundant computation and improve performance.

Basic Usage

from common.cache import cached, CacheConfig, EvictionPolicy

# Simple decorator usage
@cached(ttl_seconds=300.0)
def fetch_user(user_id: str) -> dict:
    return db.query(user_id)

# Detailed control with configuration object
config = CacheConfig(
    max_size=1000,
    ttl_seconds=3600.0,
    eviction_policy=EvictionPolicy.LRU,
)

@cached(config=config)
async def async_fetch(user_id: str) -> dict:
    return await db.async_query(user_id)

Preset Configurations

from common.cache import (
    DEFAULT_CACHE_CONFIG,    # Default: 1000 items, LRU
    SMALL_CACHE_CONFIG,      # Small: 100 items, 60s TTL
    LARGE_CACHE_CONFIG,      # Large: 10000 items, 1 hour TTL
    SHORT_TTL_CACHE_CONFIG,  # Short: 30s TTL
    LONG_TTL_CACHE_CONFIG,   # Long: 24 hour TTL
    NO_EVICTION_CACHE_CONFIG,  # Unlimited (use with caution)
)

@cached(config=SMALL_CACHE_CONFIG)
def frequently_accessed_data():
    return compute()

Cache Backends

Backend Description Use Case
LRUCache Least Recently Used General caching
LFUCache Least Frequently Used Prioritize frequently accessed data
TTLCache Time To Live based Time-based expiration
InMemoryCache Simple memory cache Unlimited caching

Eviction Policies

Policy Description
LRU Remove least recently accessed items
LFU Remove least frequently accessed items
TTL Remove based on expiration time
FIFO Remove first-in items first
NONE No eviction (unlimited)

Builder Pattern

from common.cache import CacheConfig, EvictionPolicy

config = CacheConfig()
config = config.with_max_size(500)
config = config.with_ttl(300.0)
config = config.with_eviction_policy(EvictionPolicy.LFU)
config = config.with_namespace("users")
config = config.with_name("user_cache")

Key Generators

from common.cache import (
    cached,
    DefaultKeyGenerator,
    ArgumentKeyGenerator,
    CallableKeyGenerator,
)

# Use specific arguments for key generation
@cached(
    key_generator=ArgumentKeyGenerator(arg_names=("user_id",)),
)
def get_user(user_id: str, include_details: bool = False):
    return db.query(user_id)

# Custom key generation
def custom_extractor(func, args, kwargs):
    return f"user:{kwargs.get('user_id', 'default')}"

@cached(
    key_generator=CallableKeyGenerator(custom_extractor),
)
def get_user_data(user_id: str):
    return db.query(user_id)

Hooks

from common.cache import cached, LoggingCacheHook, MetricsCacheHook

# Logging hook
logging_hook = LoggingCacheHook()

# Metrics hook
metrics_hook = MetricsCacheHook()

@cached(ttl_seconds=60.0, hooks=[logging_hook, metrics_hook])
def monitored_fetch(key: str):
    return compute(key)

# Query metrics
print(metrics_hook.hits)       # Cache hit count
print(metrics_hook.misses)     # Cache miss count
print(metrics_hook.hit_rate)   # Hit rate (0.0 ~ 1.0)
print(metrics_hook.evictions)  # Evicted item count

Registry Usage

from common.cache import get_cache, CacheRegistry

# Get cache from global registry
cache = get_cache("users", config=CacheConfig(max_size=1000))
cache.set("user:1", user_data)
user = cache.get("user:1")

# Registry management
registry = CacheRegistry()
registry.clear_all()
stats = registry.get_all_stats()

Utility Functions

from common.cache import cache_get, cache_set, cache_delete, cache_clear, cache_stats

# Use convenience functions
cache_set("users", "user:1", user_data, ttl_seconds=300.0)
user = cache_get("users", "user:1", default=None)
cache_delete("users", "user:1")
cache_clear("users")

# Query statistics
stats = cache_stats("users")
print(f"Hit rate: {stats.hit_rate:.2%}")
print(f"Size: {stats.size}/{stats.max_size}")

Exception Handling

from common.cache import cached, CacheKeyError, CacheAction

# RAISE action: raise exception on cache miss
config = CacheConfig(on_miss=CacheAction.RAISE)

@cached(config=config)
def strict_fetch(key: str):
    return compute(key)

try:
    result = strict_fetch("missing")
except CacheKeyError as e:
    print(f"Cache key '{e.key}' not found")
    result = default_value

CacheExecutor

from common.cache import CacheExecutor, CacheConfig

config = CacheConfig(max_size=100, ttl_seconds=60.0)
executor = CacheExecutor(config)

# Synchronous function
result = executor.execute(compute_function, arg1, arg2)

# Asynchronous function
result = await executor.execute_async(async_compute, arg1, arg2)

# Cache control
executor.invalidate("key")
executor.clear()

CacheStats

from common.cache import CacheStats

stats: CacheStats = cache.get_stats()
print(f"Size: {stats.size}")
print(f"Max size: {stats.max_size}")
print(f"Hits: {stats.hits}")
print(f"Misses: {stats.misses}")
print(f"Hit rate: {stats.hit_rate:.2%}")
print(f"Evictions: {stats.evictions}")