Migration Guide
Migrating from v2.0 to v2.1
v2.1 is fully backwards compatible with v2.0. No code changes are required. All new features are opt-in via new parameters.
New Features (Opt-In)
Disk Persistence: Add
backend=DiskBackend(path)to any cache constructor# Before (v2.0): in-memory only cache = AsyncCache(maxsize=1000, default_ttl=300) # After (v2.1): add persistence, zero other changes from cache import DiskBackend cache = AsyncCache(maxsize=1000, default_ttl=300, backend=DiskBackend("/tmp/cache.pkl"))
Invalidation Decorators: New
AsyncLRUInvalidator/AsyncTTLInvalidator# Before: manual invalidation get_user.invalidate_cache(user_id) # After: declarative invalidation decorator @AsyncLRUInvalidator(get_user) async def update_user(user_id, data): ...
Benchmarks: New
benchmarks/run.pyscript
Breaking Changes in v2.2
Invalidators: ``skip_args`` removed. Passing
skip_argstoAsyncLRUInvalidator,AsyncTTLInvalidator, orAgentCacheInvalidatornow raisesTypeError. Usekey_fninstead:# Before (v2.1): @AsyncLRUInvalidator(get_data, skip_args=1) async def update_data(self, key): ... # After (v2.2): @AsyncLRUInvalidator(get_data, key_fn=lambda args, kw: (args[1:], {})) async def update_data(self, key): ...
Invalidation fires before the mutation. Previously invalidation happened after the mutation returned. Now it fires before
await func(...), guaranteeing no reader ever sees stale data even if the mutation raises. This is a semantic change — code that relied on seeing stale data during the mutation should be updated.``AgentCacheInvalidator`` new params.
AgentCacheInvalidatornow acceptsclear_all(defaultTrue) andkey_fnfor selective invalidation, matching the decorator invalidators’ API.
Migrating from Other Libraries
From functools.lru_cache
# Before
from functools import lru_cache
@lru_cache(maxsize=128)
def get_data(key):
return db.query(key)
# After
from cache import AsyncLRU
@AsyncLRU(maxsize=128)
async def get_data(key):
return await db.query(key)
From aiocache
# Before
from aiocache import cached
@cached(ttl=60)
async def get_data(key):
return await db.query(key)
# After
from cache import AsyncTTL
@AsyncTTL(time_to_live=60)
async def get_data(key):
return await db.query(key)
From cachetools
# Before
from cachetools import TTLCache
cache = TTLCache(maxsize=1000, ttl=300)
def get_data(key):
if key in cache:
return cache[key]
val = db.query(key)
cache[key] = val
return val
# After: async-native, thundering herd protection included
from cache import AsyncCache
cache = AsyncCache(maxsize=1000, default_ttl=300)
async def get_data(key):
return await cache.get(key, loader=lambda: db.query(key))
From dogpile.cache
# Before
from dogpile.cache import make_region
region = make_region().configure('dogpile.cache.memory')
@region.cache_on_arguments()
def get_data(key):
return db.query(key)
# After
from cache import AsyncLRU
@AsyncLRU(maxsize=1000)
async def get_data(key):
return await db.query(key)