store_backend: redis and every replica of your gateway admits the same webhook exactly once, so a duplicate delivery never runs your agent twice.
Quick Start
1
Single replica — nothing to do
One gateway process dedups with the durable SQLite default. Nothing to set.
2
Multiple replicas — set store_backend: redis
Two or more gateway processes need a shared claim so the same webhook fanned to both is admitted only once. Set it in
gateway.yaml and make sure a Redis URL is configured — the store reuses the gateway’s push RedisConfig.3
Or wire it in Python
Pass the same
store_backend through the gateway’s hooks config where you construct it.How It Works
Each replica claims the key(platform, account, channel_id, message_id) with a single SET NX PX; the first wins and the duplicate is rejected.
Fail-Open on Redis Outage
The store never wedges inbound delivery — it degrades to best-effort and surfaces the fact, never a silent green. Two failure modes, both surfaced under thedurability:idempotency degraded owner:
When to Enable
Configuration Options
The operator selects the backend and the store reuses the gateway’s pushRedisConfig — no separate idempotency Redis knob.
Gateway Turn Lock
The sibling shared-state knob that wires the same
RedisConfig.Best Practices
Enable the turn lock and idempotency together
Enable the turn lock and idempotency together
For a multi-replica gateway, set both
turn_lock.backend: redis and hooks.idempotency.store_backend: redis — one serialises a session’s turns, the other admits each webhook exactly once.Reuse the gateway's push RedisConfig
Reuse the gateway's push RedisConfig
The store auto-shares
push.redis. Configure Redis once; do not duplicate the connection for idempotency.Watch for durability:idempotency
Watch for durability:idempotency
A
durability:idempotency entry in gateway doctor / GET /health means dedup fell back or is best-effort. Alert on it the same way you alert on a degraded channel.Enable it before raising the replica count
Enable it before raising the replica count
Switch to
store_backend: redis before scaling past one replica, so a fanned-out webhook is deduped from the first extra pod.Related
Gateway Turn Lock
Sibling shared state — a distributed lease that serialises a session’s turns.
Gateway State Durability
The default SQLite dedup path and the degraded surface it joins.
Gateway Inbound Hooks
Where
store_backend is configured on the inbound hook surface.Degraded Capabilities
Where the
durability:idempotency fact surfaces.
