Cache (lexigram-cache)
Multi-backend caching system for Lexigram Framework — Redis, Memcached, and in-memory caching.
Overview
Section titled “Overview”Multi-backend async caching for the Lexigram Framework. Supports Redis, in-memory,
and Memcached backends with stampede protection, circuit breaker, Result-aware
caching, and domain model round-trip serialization.
Configure backends via CacheModule.configure() and inject CacheBackendProtocol
into any service. The @cacheable decorator provides cache-aside logic with
automatic key generation and Result support.
Install
Section titled “Install”uv add lexigram-cache# Optional extrasuv add "lexigram-cache[redis,memcached,semantic]"Quick Start
Section titled “Quick Start”from lexigram import Applicationfrom lexigram.di.module import Module, modulefrom lexigram.cache import CacheModule, CacheConfigfrom lexigram.cache.config import CacheBackendConfigfrom lexigram.cache.types import BackendTypefrom lexigram.contracts.infra.cache import CacheBackendProtocol
@module(imports=[ CacheModule.configure( CacheConfig( backends=[ CacheBackendConfig( name="default", type=BackendType.REDIS, default=True, redis_url="redis://localhost:6379/0", ) ] ) )])class AppModule(Module): pass
async def main(): async with Application.boot(modules=[AppModule]) as app: cache = await app.container.resolve(CacheBackendProtocol) await cache.set("greeting", "hello", ttl=60) value = await cache.get("greeting") print(value) # "hello"
if __name__ == "__main__": import asyncio asyncio.run(main())Configuration
Section titled “Configuration”Zero-config usage: Call
CacheModule.configure()with no arguments to use defaults (in-memory backend).
Option 1 — YAML file
Section titled “Option 1 — YAML file”cache: enabled: true backends: - name: redis type: redis default: true redis_url: "redis://localhost:6379/0" default_ttl: 300 service: enable_protection: trueOption 2 — Profiles + Environment Variables (recommended)
Section titled “Option 2 — Profiles + Environment Variables (recommended)”export LEX_CACHE__ENABLED=trueexport LEX_CACHE__BACKENDS__0__TYPE=redisexport LEX_CACHE__BACKENDS__0__REDIS_URL=redis://localhost:6379/0Option 3 — Python
Section titled “Option 3 — Python”from lexigram.cache import CacheModule, CacheConfigfrom lexigram.cache.config import CacheBackendConfigfrom lexigram.cache.types import BackendType
CacheModule.configure( CacheConfig( backends=[ CacheBackendConfig( name="redis", type=BackendType.REDIS, default=True, redis_url="redis://localhost:6379/0", ) ] ))Config reference
Section titled “Config reference”| Field | Default | Env var | Description |
|---|---|---|---|
enabled | True | LEX_CACHE__ENABLED | Enable the cache module |
backends[].name | — | LEX_CACHE__BACKENDS__0__NAME | Unique backend name |
backends[].type | — | LEX_CACHE__BACKENDS__0__TYPE | Backend type: redis, memory, memcached |
backends[].redis_url | — | LEX_CACHE__BACKENDS__0__REDIS_URL | Redis connection URL |
backends[].default_ttl | null | LEX_CACHE__BACKENDS__0__DEFAULT_TTL | Default TTL in seconds |
service.enable_protection | True | LEX_CACHE__SERVICE__ENABLE_PROTECTION | Stampede protection |
service.circuit_breaker_enabled | False | LEX_CACHE__SERVICE__CIRCUIT_BREAKER_ENABLED | Circuit breaker on backend failures |
Module Factory Methods
Section titled “Module Factory Methods”| Method | Description |
|---|---|
CacheModule.configure(...) | Configure with explicit CacheConfig |
CacheModule.stub() | In-memory backend for unit testing |
Key Features
Section titled “Key Features”- Multi-backend — Redis, in-memory, and Memcached with a unified protocol
- Stampede protection — Distributed lock on cold reads prevents thundering herd
- Circuit breaker — Opens on repeated backend failures, falls through to origin
@cacheabledecorator — Cache-aside with automatic key generation and Result support- Domain model serialization — Type-tagged JSON envelope preserves type identity round-trip
- Production security — Blocks insecure Redis passwords when LEX_ENV=production
Testing
Section titled “Testing”async with Application.boot(modules=[CacheModule.stub()]) as app: cache = await app.container.resolve(CacheBackendProtocol) await cache.set("key", "value", ttl=60) assert await cache.get("key") == "value"Key Source Files
Section titled “Key Source Files”| File | What it contains |
|---|---|
src/lexigram/cache/module.py | CacheModule with configure() and stub() |
src/lexigram/cache/config.py | CacheConfig, CacheBackendConfig, CacheServiceConfig |
src/lexigram/cache/di/provider.py | CacheProvider boot and registration |
src/lexigram/cache/decorators.py | @cacheable decorator |
src/lexigram/cache/backends/ | Redis, in-memory, and Memcached implementations |