redis backend extends that guarantee across every replica.
Quick Start
Theredis backend needs the async Redis client:
1
Single replica — already correct, no config
One gateway process serialises turns with the in-process default. Nothing to set.
2
Multiple replicas — switch the backend to redis
Two or more gateway processes sharing a session need a distributed lease so two pods can’t run one session’s turns at once.
3
Or configure it in gateway.yaml
How It Works
The lock isLockMap-compatible: one .get(session_id) call returns an async context manager that holds a cluster-wide lease for the whole async with block, and a crashed holder’s lease expires after ttl so a healthy session is never wedged.
Release is owner-checked and idempotent: only the exact owner token that claimed the lease may release it, so an expired or reclaimed lease is a harmless no-op, never another replica’s lease.
Fail-open on Redis outage
A live turn is never blocked by Redis being down — the lock degrades to a localasyncio.Lock for that turn and records a degraded capability you find later.
While degraded, turns serialise per-process only (cross-replica ordering pauses until Redis recovers). The lock records a degraded capability entry (owner_kind="capability", owner_id="turn_lock:redis") and clears it automatically on the first successful reconnect.
Health & observability
The fail-open behaviour surfaces through the same tools that report every other degraded gateway capability.praisonai gateway doctor— lists thecapability/turn_lock:redisdegraded owner with a redacted reason.- Gateway
health()//health— the same degraded entry, machine-readable. - Logs — a
WARNING: Distributed turn lock degraded to local-only (Redis unavailable): …on the first outage.
Extensible Doctor
How
praisonai gateway doctor reports degraded capabilities.Gateway Liveness
Companion health signal — reap half-open connections.
Configuration Options
TurnLockConfig from praisonaiagents/gateway/config.py.
The
enabled property returns True only when a distributed backend is selected (backend != "local").
Lease keys are namespaced as
{RedisConfig.prefix}turnlock:{session_id}, defaulting to praison:turnlock: when no prefix is set. Operators sharing one Redis across environments should set distinct RedisConfig.prefix values so leases never collide.TurnLockConfig Reference
Full field, type, and default reference for
TurnLockConfig.GatewayConfig Reference
The parent config that wires
turn_lock into the gateway.When to Enable
Enableredis whenever more than one gateway process can share a session — replica count alone decides it.
You need backend: 'redis' whenever more than one gateway process shares a session — with or without an identity resolver. A single-adapter deployment with replicas > 1 still wires the distributed backend.
Backward Compatibility
local is the default and reproduces today’s in-process asyncio.Lock byte-for-byte — single-replica deployments are unchanged and add no new dependency.
Best Practices
Size ttl to survive one Redis blip; renewal covers long turns
Size ttl to survive one Redis blip; renewal covers long turns
The lease auto-renews at ~
ttl/3 while a turn runs, so a turn longer than ttl never lets another replica claim the same session. Size ttl to survive a brief Redis blip, not your slowest turn — the default 60.0 suits most deployments.Reuse the gateway's RedisConfig unless you need a separate store
Reuse the gateway's RedisConfig unless you need a separate store
Leave
url unset and the distributed lock reuses the gateway’s configured RedisConfig. Set url only when the lock lives on a different Redis than push/delivery — when both are set, url wins.Watch the doctor for a degraded turn lock
Watch the doctor for a degraded turn lock
On a Redis outage the lock fails open and records a
turn_lock:redis degraded capability. Check praisonai gateway doctor or /health — a persistent entry means cross-replica ordering is paused until Redis recovers.Enable it before you scale, not after
Enable it before you scale, not after
Flip
backend='redis' before raising replicaCount. Scaling first leaves a window where two pods run concurrent turns on one session.Related
Gateway Durability
The wider “never lose or double-run a turn” story this fits into.
Gateway Degraded Channels
The symmetric fail-open pattern for a degraded delivery channel.
Cross-Platform Sessions
The in-process turn lock this extends across replicas.
Helm Chart (Gateway)
Scale the gateway on Kubernetes with
replicaCount.Gateway Admission Control
Sibling robustness knob — concurrency ceiling and backpressure.
Gateway Turn Executor
Sibling robustness knob — place a session’s turn on its own worker.
See also — idempotency
store_backend: redis. Because the turn lock has a real Redis backend, operators often expect the inbound idempotency store to mirror it. It does not have a Redis backend yet — setting store_backend: redis falls back to durable SQLite and records a degraded fact. See Gateway Hooks → Multi-replica gateways for what happens if you set it.
