Caching & Distributed Locks
Relevant source files
The following files were used as context for generating this wiki page:
The Caching and Distributed Locks system in Forze provides a standardized, contract-based approach to managing temporary data and concurrency across distributed environments. By abstracting infrastructure details into logical specifications, the framework allows developers to implement read-through caching, stampede protection, and resource locking without coupling business logic to specific backends like Redis.
Sources: skills/forze-framework-usage/SKILL.md, examples/recipes/cache_reads/app.py
Caching System
The caching architecture is built around the CacheSpec, which defines the behavior of a cache instance independently of its physical implementation. This system supports advanced features like probabilistic early refresh and multi-level (L1/L2) caching strategies.
Cache Specification
A CacheSpec acts as a logical route for cache operations. It defines TTL (Time To Live), namespaces, and advanced invalidation logic.
PRODUCT_SPEC = DocumentSpec(
name="products",
read=ProductRead,
write=DocumentWriteTypes(...),
cache=CacheSpec(name="products", ttl=timedelta(minutes=5)),
)
Sources: examples/recipes/cache_reads/app.py:65-73, src/forze/application/contracts/cache/specs.py
Caching Tiers and Strategies
Forze supports sophisticated caching patterns to optimize performance and prevent backend overload:
- Stampede Protection: Concurrent cache misses for the same key collapse into a single request per process.
- L1 Caching: An optional in-process cache tier that skips network round-trips. It uses a cross-replica staleness budget defined by a secondary TTL.
- Probabilistic Early Refresh: Uses a "beta" parameter to refresh entries before they expire, reducing the likelihood of a blocking miss.
- Adaptive TTL: Supports
AgeBasedTtl(proportional to document age) andsliding_ttl(extension on hit, requiring Redis 7+).
Sources: skills/forze-documents-search/SKILL.md, src/forze/application/contracts/cache/specs.py
Redis Cache Adapter
The RedisCacheAdapter implements the CachePort using a Redis backend. It manages serialization, namespace partitioning, and key-level TTL overrides.
Distributed Locks
Distributed locks (DLocks) provide mutual exclusion across multiple instances of an application. In Forze, these are typically handled via the Redis integration using the RedisDistributedLockAdapter.
Locking Mechanics
Distributed locks are requested via a DistributedLockPort. The implementation ensures that only one worker can hold a lock for a specific resource at a time, preventing race conditions in distributed tasks or sagas.
| Feature | Description |
|---|---|
| Namespace Isolation | Locks are partitioned by namespace to prevent key collisions between different resource types. |
| TTL Enforcement | Locks automatically expire to prevent deadlocks if a process crashes while holding a lock. |
| Redis Backend | Uses Redis primitives to ensure atomic lock acquisition and release. |
Sources: src/forze_redis/adapters/dlock.py, skills/forze-specs-infrastructure/SKILL.md
Wiring and Configuration
Distributed locks and caches are registered within the RedisDepsModule. Configuration maps logical names to physical Redis namespaces.
redis_module = RedisDepsModule(
client=redis_client,
caches={ResourceName.PROJECTS: {"namespace": "app:projects"}},
dlocks={ResourceName.PROJECTS: {"namespace": "app:projects:locks"}},
)
Sources: skills/forze-specs-infrastructure/SKILL.md
Data Flow: Read-Through Cache
The following diagram illustrates the sequence of events during a read-through operation where the cache is checked before falling back to the primary data store.
Configuration Reference
Cache Configuration Options
The following table summarizes key configuration parameters available in CacheSpec and RedisCacheConfig.
| Option | Type | Description |
|---|---|---|
name | str | StrEnum | Logical name used for dependency routing. |
ttl | timedelta | Global expiration time for cache entries. |
namespace | str | Physical prefix used in the Redis store. |
early_refresh_beta | float | Parameter for probabilistic early refresh (default 1.0). |
l1 | L1Spec | Configuration for optional in-process caching. |
Sources: src/forze/application/contracts/cache/specs.py, examples/recipes/cache_reads/app.py
Caching and Distributed Locks in Forze ensure that applications remain resilient and performant under load. By utilizing the ExecutionContext to resolve these ports, developers maintain a strict separation between domain logic and infrastructure, allowing for seamless transitions between different caching backends or locking strategies as the system scales.