aiocache

Asyncio cache manager with a unified async API across memory, Valkey/Redis, and Memcached backends

Library
PyPI
v0.12.3
1,437stars
BSD 3-Clause License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
56/100Fair
Development Activity28
Maintenance24
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
82/100Excellent
Architecture78
Code Quality80
Innovation78
Learning Curve90

aiocache is an asyncio-native caching library for Python that gives you one consistent API for storing and retrieving values regardless of which backend sits behind it — in-process memory, Valkey/Redis, or Memcached. Every cache exposes the same core operations (get, set, multi_get, multi_set, add, increment, exists, delete, clear, raw) so switching backends in production is a configuration change rather than a rewrite.

Beyond basic key/value storage, aiocache ships cached, cached_stampede, and multi_cached decorators for memoizing async function calls, a pluggable serializer layer (string, pickle, JSON, msgpack) for storing arbitrary Python objects, a plugin/hooks system for instrumenting cache operations, and a Redlock-based distributed locking implementation to prevent cache stampedes when many callers race to repopulate the same key.

What You Get

  • A unified async cache interface (get, set, multi_get, multi_set, add, increment, delete, clear, exists, raw) implemented consistently across all backends
  • Three built-in backends — SimpleMemoryCache, ValkeyCache (Valkey/Redis via valkey-glide), and MemcachedCache (via aiomcache) — installed as optional extras
  • cached, cached_stampede, and multi_cached decorators for transparently memoizing async function results with configurable TTL and key builders
  • A serializer layer (StringSerializer, PickleSerializer, JsonSerializer, MsgPackSerializer) so any Python object can be cached, not just strings
  • A plugin/hooks system (BasePlugin) for adding cross-cutting behavior like timing or hit/miss ratio tracking around cache commands
  • A RedLock distributed-locking implementation backing cached_stampede, stopping many concurrent callers from all recomputing the same expensive value at once

Common Use Cases

  • Caching expensive async API/database calls behind a simple @cached decorator instead of hand-writing get/set boilerplate
  • Running the same caching code in local dev against SimpleMemoryCache and in production against ValkeyCache/MemcachedCache with no code changes
  • Preventing cache stampedes on hot keys in high-traffic async services using cached_stampede and RedLock
  • Storing complex Python objects (namedtuples, dataclasses) in Redis/Valkey via PickleSerializer or MsgPackSerializer instead of only strings
  • Adding request-level or endpoint-level response caching to asyncio web frameworks like aiohttp, Sanic, or Tornado

Under The Hood

Architecture aiocache is organized around a generic BaseCache ABC (aiocache/base.py) whose API helper class registers and wraps command methods with cross-cutting decorators — timeout enforcement, an AIOCACHE_DISABLE env-var kill switch, and before/after plugin hooks — before dispatching to backend-specific private methods (_get, _set, _multi_get, _increment, _expire, _redlock_release, etc.) implemented separately in aiocache/backends/memory.py, valkey.py, and memcached.py. Serializers (aiocache/serializers/) and plugins (aiocache/plugins.py) are injected at construction time and centralize object (de)serialization and observability away from the backend logic itself. On top of this sits aiocache/decorators.py (cached, cached_stampede, multi_cached), which builds cache keys, calls into BaseCache, and for stampede protection coordinates with the Redlock implementation in aiocache/lock.py. Because every backend and decorator depends on the exact private method contract and the API registration mechanism, changing that base command-dispatch chain would ripple through all three backends and every decorator at once.

Tech Stack The core library is pure Python 3.9+ built on the asyncio standard library with zero required runtime dependencies; backend support is opt-in via extras — valkey-glide>=2.0.0 for ValkeyCache (Redis/Valkey protocol), aiomcache>=0.5.2 for MemcachedCache, and msgpack>=0.5.5 for the MsgPack serializer. Packaging uses classic setup.py/setup.cfg (pyproject.toml only carries Black’s config), linting runs through flake8 and a strict .mypy.ini (disallow_any_generics, disallow_incomplete_defs, disallow_untyped_decorators, warn_unreachable), pre-commit hooks enforce these locally, and GitHub Actions (ci.yml, codeql.yml) run lint, type-check, and test jobs on every push. Docs are built with Sphinx and published on Read the Docs.

Code Quality The project has an extensive pytest suite spanning tests/ut (unit tests per module, including per-backend subtests), tests/acceptance, and tests/performance, with fixtures in conftest.py for spinning up real Valkey/Memcached configs. Type hints are pervasive and shipped via a py.typed marker, checked under a notably strict mypy profile with relaxed rules carved out specifically for the tests.* package. Naming is consistent (leading-underscore private backend methods implementing a public ABC contract), error handling is explicit (typed exceptions in exceptions.py, ValueError/TypeError raised deliberately in backend methods rather than swallowed), and CI enforces lint plus type-checking on every change.

API Design aiocache optimizes hard for the common case: SimpleMemoryCache() then await cache.get/set(...) works with no configuration, and everyday caching of an async function reduces to a single @cached(cache, ttl=60) line. Naming is uniform across all three backends, so migrating from memory to Valkey/Redis in production is a one-line swap rather than a rewrite. Extending the library with a custom backend is less friction-free — it requires understanding and implementing the underscore-prefixed private method contract of BaseCache, which leaks internal wiring to subclass authors — but for the primary use case (drop-in async caching and memoization) the surface area is small and consistent.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search