Redis Storage
Production-grade FSM storage using Redis with Pydantic validation, circuit breaker protection, and atomic compare-and-set via WATCH/MULTI/EXEC transactions.
Setup
import redis.asyncio as redis
from pyrogram_patch.fsm import RedisStorage
redis_client = redis.Redis(
host="localhost",
port=6379,
db=0,
decode_responses=True,
)
storage = RedisStorage(redis_client, prefix="mybot:fsm:")Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
redis | redis.asyncio.Redis | — | Async Redis client instance |
prefix | str | "pyrogram_patch:" | Key prefix for all FSM entries |
Circuit Breaker Integration
Every Redis operation is wrapped in a circuit breaker. If Redis becomes unavailable, the breaker opens and prevents flooding a dead connection. Once Redis recovers, the breaker transitions through HALF_OPEN back to CLOSED automatically.
Configure via PyrogramPatchConfig.circuit_breaker (environment variables or code):
# Environment variables:
# PYROGRAM_PATCH_CIRCUIT_BREAKER__FAILURE_THRESHOLD=5
# PYROGRAM_PATCH_CIRCUIT_BREAKER__SUCCESS_THRESHOLD=2
# PYROGRAM_PATCH_CIRCUIT_BREAKER__TIMEOUT=30
# PYROGRAM_PATCH_CIRCUIT_BREAKER__FALLBACK_MESSAGE="Service temporarily unavailable"Pydantic Validation
State data is validated at write time using FSMStateModel (a Pydantic model). Invalid payloads are rejected before touching Redis, preventing corrupt state.
Atomic Compare-and-Set
Uses Redis WATCH/MULTI/EXEC transactions for safe concurrent updates. The compare_and_set() method reads the current state, verifies it matches the expected value, then atomically writes the new value — all inside a transaction. If another client modifies the key between WATCH and EXEC, the transaction fails and returns False.
# Used internally by RateLimitMiddleware for safe counter increments
success = await storage.compare_and_set(
id="ratelimit:user:12345:1700000",
new_state={"count": 4},
expected_state={"count": 3},
ttl=60,
)