Scaling¶
Strategies for scaling Reflex beyond single-instance deployments.
🏗️ Current Architecture¶
The default implementation uses PostgreSQL's LISTEN/NOTIFY for real-time event delivery.
Good For
- Single-region deployments
- Moderate throughput (thousands of events/second)
- Teams wanting minimal infrastructure
📈 Horizontal Scaling¶
The design supports multiple concurrent consumers out of the box:
flowchart LR
LB["Load Balancer"]
subgraph Instances
A1["Agent 1"]
A2["Agent 2"]
A3["Agent 3"]
end
PG[("PostgreSQL")]
LB --> A1
LB --> A2
LB --> A3
A1 --> PG
A2 --> PG
A3 --> PG Events are claimed with FOR UPDATE SKIP LOCKED, preventing duplicate processing across instances.
Required Configuration
Enable distributed locking when running multiple instances:
🚀 Scaling Beyond PostgreSQL¶
For higher scale requirements, the EventStore interface is designed to be swappable.
Redis Streams¶
Recommended for high throughput scenarios:
Future: Redis-backed EventStore
class RedisEventStore:
"""Drop-in replacement using Redis Streams."""
async def publish(self, event: Event) -> str:
...
async def subscribe(self, event_types: list[str]) -> AsyncIterator[Event]:
...
| Benefit | Description |
|---|---|
| Higher throughput | 100k+ events/second |
| Consumer groups | Built-in load balancing |
| Persistence | Optional with AOF/RDB |
| Fan-out | Native pub/sub patterns |
Migration Path¶
- Implement
RedisEventStorewith same interface - Add
EVENT_BACKENDconfig option (postgres|redis) - Swap implementation in dependency injection
- PostgreSQL remains for event history/replay
✅ Scaling Checklist¶
- [x] Default configuration works
- [x] PostgreSQL handles events and locking
- [ ] Consider Logfire for observability
- [x] Set
LOCK_BACKEND=postgres - [x] Configure pool size:
DB_POOL_MAX = total_instances × 5 - [x] Use load balancer for API traffic
- [x] Monitor DLQ for failed events
- [x] Implement Redis EventStore
- [x] Separate read/write database replicas
- [x] Add caching layer for hot data
- [x] Consider event batching
⚙️ Pool Sizing¶
Configure connection pool based on instance count: