Gateway State Durability
The gateway's webhook idempotency and session history are durable by default — a restart no longer re-processes webhooks or drops history
The gateway’s webhook idempotency and session history are durable by default — a restart no longer re-processes webhooks or drops history.
from praisonaiagents import Agent
from praisonai.gateway import Gateway
agent = Agent(name="assistant", instructions="Be helpful.")
gw = Gateway(agents=[agent])
gw.register_hook({"path": "alerts", "agent": "assistant", "auth": "secret"})
gw.start() # webhook idempotency + session history are durable by defaultWhen a durable store cannot initialise, the gateway logs, records a redacted gateway / durability:* degraded owner, and keeps serving in-memory so inbound delivery never stops.
What’s Durable, Out of the Box
| State | Backend | Location |
|---|---|---|
| Webhook idempotency | SQLite | ~/.praisonai/state/hook_idempotency.sqlite |
| Session history | The configured get_default_session_store() | See Gateway Session Persistence |
Both survive a routine gateway restart. Webhook dedup keys persist across a redelivery window, and session history is not dropped when the process cycles.
Quick Start
- Start the gateway — durable by default
python from praisonaiagents import Agent from praisonai.gateway import Gateway agent = Agent(name="assistant", instructions="Be helpful.") gw = Gateway(agents=[agent]) gw.register_hook({"path": "alerts", "agent": "assistant", "auth": "secret"}) gw.start() # webhook idempotency + session history are durable by defaultNo configuration is required — the SQLite idempotency store and the configured session store are used automatically.
- Opt out for tests / ephemeral runs
yaml hooks: idempotency: store_backend: memory # explicit opt-out — tests / ephemeral runs only hooks: - path: alerts agent: assistant # ..."memory"keeps the old in-memory behaviour when you don’t want an on-disk store. - See a degraded fallback
If a durable store cannot initialise, the boundary keeps serving in-memory and records a degraded owner:
json { "owner_kind": "gateway", "owner_id": "durability:idempotency", "state": "cold", "reason": "durable idempotency store unavailable (running in-memory)", "retry_hint": "praisonai gateway doctor --fix" }It surfaces in
praisonai gateway statusunderDegraded:and inGET /healthunderdegraded_owners. - Recover
bash praisonai gateway doctor --fixRun the sanctioned repair, or hot-reload a config that fixes the store path — either clears the degraded entry automatically on the next successful build.
What Happens on Init Failure
When a durable store genuinely cannot initialise, the boundary that owns it (the praisonai-bot wrapper, praisonai_bot.bots._session):
- Logs the failure with the raw store path (log only).
- Records a
gateway/durability:*degraded owner with a redacted reason and thepraisonai gateway doctor --fixhint. - Continues serving in-memory so inbound delivery keeps working.
- Auto-clears the degraded owner on the next successful (re)build of the durable store.
The two owners:
owner_id | Meaning |
|---|---|
durability:idempotency | Durable webhook-idempotency store unavailable; dedup does not survive restart. |
durability:session | Durable session store unavailable; session history does not survive restart. |
On the healthy path — store_backend: redis with Redis reachable — there is no durability:idempotency fact: the cross-replica store gives cluster-wide exactly-once admission. The owner only appears when the store degrades, carrying one of three reasons:
| Reason | Meaning |
|---|---|
"durable idempotency store unavailable (running in-memory)" | The durable SQLite store could not initialise; dedup is per-process and does not survive restart. The most severe of the three. |
"redis idempotency backend not available (running per-replica)" | The operator asked for cross-replica dedup via store_backend: redis, but Redis was unreachable (or the redis package is missing) at build time; the wrapper fell back to the durable SQLite store and runs per-replica. Cross-replica dedup only holds if replicas share the SQLite state file. See Gateway Cross-Replica Idempotency. |
"redis idempotency backend unreachable at runtime (dedup best-effort until it recovers)" | Redis was reachable at build time but dropped later. The store fails open — it admits the delivery rather than 500-ing the hook path — so cross-replica dedup is temporarily best-effort. The fact auto-clears on the next successful Redis op after recovery. |
How to See It
CLI
$ praisonai gateway status
...
Degraded:
✗ gateway:durability:idempotency — durable idempotency store unavailable (running in-memory) fix: praisonai gateway doctor --fixAlways printed when degraded_owners is non-empty (not gated on --deep).
Health endpoint
curl http://127.0.0.1:8765/healthThe same fact appears under degraded_owners:
{
"degraded_owners": [
{
"owner_kind": "gateway",
"owner_id": "durability:idempotency",
"state": "cold",
"reason": "durable idempotency store unavailable (running in-memory)",
"retry_hint": "praisonai gateway doctor --fix"
}
]
}Agent tool
from praisonaiagents import Agent
from praisonaiagents.tools import gateway_status
agent = Agent(
name="assistant",
instructions="Call gateway_status; warn if a durability owner is degraded.",
tools=[gateway_status],
)An agent inside the gateway can read the same degraded_owners via gateway_status.
Best Practices
Keep the default — durable — in production
Leave store_backend unset (or sqlite). Only set memory for tests or explicitly ephemeral runs, where losing dedup on restart is acceptable.
Alert on any durability:* owner
A durability:idempotency or durability:session entry in degraded_owners means state is not surviving restart. Alert on it the same way you alert on a degraded channel or provider.
Recover with the sanctioned action
praisonai gateway doctor --fix is the one command in the retry_hint. A hot-reload that repairs the store path also clears the entry automatically — no manual clear step.
Trust the redaction
The operator-facing reason never contains the raw store path — that stays in the log. Safe to render straight to a dashboard or status probe.
Related
Webhook idempotency configuration and the durable-by-default dedup store.
Cross-Replica IdempotencyExactly-once webhook admission across every gateway replica via Redis.
Degraded CapabilitiesThe unified degraded_owners surface these durability facts join.
gateway status Degraded: section and gateway doctor --fix.