Gateway Reliability Preset
One switch that composes graceful drain + admission control for production gateways
You now get backpressure by default. Leaving reliability unset gives you a bounded admission ceiling, a fair wait queue, strict outbound ordering, and a drain window sized to the bind — no argument required.
from praisonaiagents import Agent
from praisonai_bot.bots.botos import BotOS
# Safe by default: admission ceiling + fair queue + drain, bind-aware.
BotOS(
agent=Agent(name="SupportBot", instructions="Help users with support questions."),
platforms=["telegram", "discord"],
)Quick Start
- Python (BotOS) — safe by default
No
reliability=argument needed — the gateway resolves a bounded admission ceiling, a fair queue, strict ordering, and a bind-aware drain:python from praisonaiagents import Agent from praisonai_bot.bots.botos import BotOS BotOS( agent=Agent(name="SupportBot", instructions="Help users."), platforms=["telegram", "discord"], ).run() - Override specific knobs
Explicit args always beat the preset — useful for canary deployments:
python BotOS( agent=Agent(name="SupportBot", instructions="Help users."), platforms=["telegram"], reliability="production", drain_timeout=30, # override: 30s instead of preset 15s ) - YAML (gateway.yaml)
yaml reliability: production # or nested under gateway: gateway: reliability: production max_concurrent_runs: 8 # explicit override still respected - CLI
bash praisonai gateway start --config gateway.yaml --reliability production
Profiles
Four distinct postures — the unset posture is bind-aware, so it appears twice.
| Preset | Drain | Admission ceiling | Wait queue | Outbound ordering | When to use |
|---|---|---|---|---|---|
Unset (reliability=None, loopback bind) | 5 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | Local dev on 127.0.0.1 / localhost — safe by default |
Unset (reliability=None, non-loopback bind) | 15 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | An actual deployment (0.0.0.0, real hostname) — full production posture is auto-picked |
"production" (explicit) | 15 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | Explicitly ask for the production window regardless of bind |
"default" (explicit) | 5 s | No | No | best-effort | Legacy behaviour — you know what you’re doing and want the pre-#3438 shape |
"off" | 0 s | No | No | best-effort | Explicit opt-out — immediate teardown, no backpressure. This is now the only way to get the pre-safe behaviour |
What Each Knob Does
Graceful drain — on BotOS.stop(), the gateway quiesces ingress and waits for in-flight agent turns to finish before cancelling tasks. The drain window is the maximum time to wait.
Inbound admission control — caps the number of concurrent agent runs across all channels. Excess turns either queue (bounded fair wait) or are rejected immediately, depending on the overflow_policy.
Precedence Ladder
Explicit constructor fields always win over the preset. Only fields left unset are filled by the preset.
CLI flag
> constructor arg (drain_timeout=, max_concurrent_runs=, admission_policy=)
> gateway.reliability YAML key
> top-level reliability: YAML key
> preset defaultExample — preset sets drain to 15s, but explicit override wins:
from praisonaiagents import Agent
from praisonai_bot.bots.botos import BotOS
BotOS(
agent=Agent(name="SupportBot", instructions="Help users."),
platforms=["telegram"],
reliability="production",
drain_timeout=30.0, # 30s wins over preset's 15s
)Which Profile Should I Pick?
Most operators pick nothing — the unset posture is safe, and a non-loopback bind auto-selects the full production window.
What Changed on Restart
Before #3442, running the gateway the obvious way gave a no-backpressure deployment that cut in-flight turns on restart. The unset posture now drains gracefully, sized to the bind.
sequenceDiagram
participant Op as Operator
participant Gw as Gateway
participant Ag as In-flight turn
Note over Op: Before #3442
Op->>Gw: praisonai gateway start (no reliability flag)
Gw-->>Op: (no admission, 5s drain)
Op->>Gw: rolling restart
Gw-->>Ag: SIGTERM — turn cut mid-response ❌
Note over Op: After #3442 (safe by default)
Op->>Gw: praisonai gateway start --host 0.0.0.0
Gw-->>Op: (admission ceiling + fair queue + 15s drain)
Op->>Gw: rolling restart
Gw-->>Ag: SIGTERM — drain window; turn completes ✅What It Does NOT Change
These are already default-on regardless of the reliability preset:
- Durable inbound journal (session level)
- Durable outbound outbox
Degraded-channel isolation is another default-on opt-out from fail-closed behaviour, independent of the reliability preset: one channel’s unavailable credential isolates just that channel instead of aborting the gateway. See Degraded Channel Isolation.
Cross-instance Redis pub/sub is self-healing: on connection loss the adapter reconnects with bounded backoff and surfaces the outage via route:redis-pubsub in degraded_owners. See Real-Time Push Notifications → HA & cross-instance delivery.
Best Practices
Pass nothing — the default is already safe
Leaving reliability unset gives you a bounded admission ceiling, a fair wait queue, strict ordering, and a bind-aware drain. On a non-loopback bind that resolves to the full production window automatically, so most deployments need no reliability= argument.
Force production to get the 15s window even on loopback
reliability="production" pins the 15 s drain regardless of bind. Use it when you test on 127.0.0.1 but want the same drain window a real deployment gets. Pair with a process manager that sends SIGTERM on deploy.
I want the pre-#3438 behaviour back
Pass reliability="off" for immediate teardown with no admission, or reliability="default" for a 5 s drain with no ceiling. off also forces gateway.durable_runs off — the explicit escape hatch to the zero-overhead path. Neither is a recommended default.
Handle admission rejection and a slower restart when upgrading
Two behaviours change observably once the unset posture becomes safe: a burst that used to fan out unboundedly now queues (or rejects when the queue is full), and a SIGTERM-then-kill loop now waits 5–15 s for in-flight turns. Downstream code that assumed the gateway never says no, and deploy scripts that expected sub-second restarts, need to account for both.
Override individual knobs when needed
If the preset drain window or admission ceiling doesn’t fit your load, pass drain_timeout= or max_concurrent_runs= directly — they always take precedence over the preset. See the Graceful Drain and Admission Control pages for the full knob reference.
Related
Drain-only knob — fine-grained drain control without the full preset
Gateway Admission ControlConcurrency ceiling, fair queue — and memory-aware backpressure with max_rss_mb
Reclaims memory from idle warm caches on cgroup-aware Linux hosts with a persistent store — no config required
Config ReloadHot-reload gateway.yaml without dropping in-flight turns
ReliabilityTask/workflow retry jitter and failure policies
Event-Loop WatchdogDetect a wedged asyncio loop and restart before it becomes a zombie
Startup WatchdogDetect a wedged pre-loop startup and restart before it becomes a zombie
Pressure TelemetryObserve whether the drain + admission preset is holding — admission, queues and loop-lag on health()
Dispatcher git calls run off the event loop and are serialised per gateway process