🚀 Quick Start
Get up and running with ZooCache in under 5 minutes.
TL;DR: Use
@cacheable()withadd_deps()inside your functions to register dependencies.
Installation
Requirements
- Python 3.10+
- No external dependencies required for in-memory mode
- Redis required for distributed mode
⚠️ Configuration (Critical!)
You must call configure() before using any cache functionality:
from zoocache import configure
# Basic: In-memory mode (simplest, for development)
configure()
# With Redis: Persistent storage
configure(storage_url="redis://localhost:6379")
# Full: Distributed caching
configure(
storage_url="redis://localhost:6379",
bus_url="redis://localhost:6379",
prefix="myapp_prod", # Namespace for isolation
default_ttl=3600, # 1 hour default TTL
)
Storage Options
| Storage | Use Case | Persistence | Installation |
|---|---|---|---|
| Memory | Development, testing | ❌ | Built-in |
| Redis | Production, distributed | ✅ | Built-in |
| LMDB | High-performance local | ✅ | Built-in |
| Storage | Bus | Use Case | Recommended For |
|---|---|---|---|
| Memory | ❌ | Development, testing | Local dev only |
| Memory | ✅ Redis | Single node with pub/sub | Not recommended |
| Redis | ❌ | Single instance | Simple deployments |
| Redis | ✅ Redis | Multi-node | ✅ Recommended for distributed |
| LMDB | ❌ | High-performance local | Single node, high throughput |
| LMDB | ✅ Redis | High-performance distributed | ✅ Best for most production |
Recommendation: For most production deployments, use LMDB for storage (high performance) with Redis for the bus (distributed invalidation).
→ See full storage configuration
Your First Cached Function
from zoocache import cacheable, invalidate, configure, add_deps
# Configure first!
configure()
@cacheable()
def get_user(uid):
add_deps([f"user:{uid}"]) # Register dependencies
# This function runs only on cache miss
return {"id": uid, "name": f"User {uid}"}
# First call: executes function, caches result
user = get_user(1)
# Output: Function executed
# Second call: returns cached result instantly
user = get_user(1)
# Output: (instant, no print)
How It Works
- First call to
get_user(1)executes the function and caches the result - Subsequent calls return the cached result immediately
- The
depsparameter defines what this cached result depends on
Invalidation
Basic Invalidation
def update_user(uid, data):
db.save(uid, data)
invalidate(f"user:{uid}") # Invalidate ALL cached results for user:uid
Hierarchical Invalidation
@cacheable()
def get_product(pid):
add_deps([f"product:{pid}"]) # Register dependencies
return db.get_product(pid)
@cacheable()
def get_reviews(pid):
add_deps([f"product:{pid}:reviews"]) # Register dependencies
return db.get_reviews(pid)
# Invalidate product AND its reviews
invalidate("product:42")
# Invalidate only reviews
invalidate("product:42:reviews")
→ Learn more about semantic invalidation
Dynamic Dependencies
Sometimes you don't know dependencies until runtime:
@cacheable()
def get_dashboard(uid):
user = db.get_user(uid)
add_deps([f"user:{uid}"])
if user.is_admin:
reports = db.get_admin_reports()
add_deps(["reports:admin"])
return {"user": user, "reports": reports}
return {"user": user}
→ Learn more about dependencies
Distributed Mode
For multi-node deployments, configure the bus:
When any node invalidates a tag, all nodes receive the message and update their local cache.
→ Learn more about distributed mode
Next Steps: Choose Your Path
🔌 FastAPI
Cache your FastAPI endpoints with @cache_endpoint.
🌐 Django
Transparent ORM caching with Django integration.
⭐ Litestar
Cache Litestar routes effortlessly.
💻 CLI
Monitor and manage your cache with the TUI.
⚙️ Configuration
Storage backends, TTL, serialization options.
🧠 Concepts
Deep dive into how ZooCache works.