Gateway Reliability Preset
One switch that composes graceful drain + admission control for the bot gateway
A BotOS(agent=..., ...) or praisonai gateway start with no reliability= argument is now safe by default — the gateway picks a bounded admission ceiling, a fair wait queue, strict outbound ordering, and a drain window sized to the bind (loopback → 5s, real interface → 15s). The reliability= preset is still there for callers who want to override that.
from praisonaiagents import Agent
from praisonai_bot.bots.botos import BotOS
agent = Agent(name="assistant", instructions="Help the user.")
# Safe by default: admission ceiling + fair queue + drain, bind-aware.
bot = BotOS(agent=agent, platforms=["telegram", "discord"])
bot.start()Quick Start
- Simplest — safe by default
No
reliability=needed. The gateway resolves admission, a fair queue, strict ordering, and a bind-aware drain:python from praisonaiagents import Agent from praisonai_bot.bots.botos import BotOS agent = Agent(name="assistant", instructions="Help the user.") # Safe by default: admission ceiling + fair queue + drain, bind-aware. bot = BotOS(agent=agent, platforms=["telegram", "discord"]) bot.start() - Force the full production window even on loopback
python bot = BotOS( agent=agent, platforms=["telegram", "discord"], reliability="production", # 15s drain regardless of bind ) - Explicit opt-out (revert to pre-#3438 immediate teardown)
python bot = BotOS( agent=agent, platforms=["telegram", "discord"], reliability="off", # no drain, no admission — you asked for it ) - YAML — set reliability: at the top level
yaml # gateway.yaml reliability: production agents: assistant: instructions: "Help the user." channels: telegram: token: "${TELEGRAM_TOKEN}"Run with:
bash praisonai gateway start --config gateway.yaml - CLI flag — override any YAML value
bash praisonai gateway start --config gateway.yaml --reliability productionThe CLI flag takes the highest precedence and overrides whatever is in the YAML file.
- Override individual settings after the preset
Explicit kwargs on
BotOSalways win over the preset:python from praisonaiagents import Agent from praisonai_bot.bots.botos import BotOS agent = Agent(name="assistant", instructions="Help the user.") bot = BotOS( agent=agent, platforms=["telegram"], reliability="production", drain_timeout=30.0, # overrides the preset's 15 s ) bot.start()
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 (None, loopback bind) | 5 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | Local dev on 127.0.0.1 / localhost |
Unset (None, non-loopback bind) | 15 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | An actual deployment (0.0.0.0, real hostname) |
"production" | 15 s | Yes (CPU-scaled) | Yes (bounded, fair) | strict | Pin the production window regardless of bind |
"default" | 5 s | No | No | best_effort | Explicit legacy posture — the pre-#3438 shape |
"off" | 0 s | No | No | best_effort | Explicit opt-out — immediate teardown, no backpressure |
The safe posture (unset) and production both enable strict per-conversation FIFO delivery on the outbox — see Outbound Ordering. "default" and "off" keep best_effort for backward compatibility.
How It Works
The resolver _reliability.py converts the profile string into concrete values for drain_timeout, max_concurrent_runs, and admission_policy. Those values are passed directly to the underlying WebSocketGateway build step.
Precedence (highest → lowest):
- Explicit kwargs on
BotOS.__init__— e.g.drain_timeout=30,outbound_ordering="strict" reliability=preset — e.g."production"- SDK defaults
outbound_ordering= is also an explicit kwarg that overrides the preset. Passing outbound_ordering="strict" (or "best_effort") always wins over the profile’s choice; unknown values raise ValueError at resolve time.
Configuration Surfaces
Python
from praisonai_bot.bots.botos import BotOS
# Minimal — safe by default, no reliability= needed
bot = BotOS(agent=agent, platforms=["telegram"])
# From a YAML config file (reads top-level `reliability:` or `gateway.reliability`)
bot = BotOS.from_config("gateway.yaml")YAML
Both placements are accepted:
# Top-level
reliability: production
# Or nested under gateway:
gateway:
reliability: production
max_concurrent_runs: 8 # explicit override still respectedCLI
praisonai gateway start --config gateway.yaml --reliability production
praisonai gateway start --config gateway.yaml --reliability off
praisonai gateway start --config gateway.yaml --reliability defaultCommon Patterns
Production deployment
A non-loopback bind auto-selects the full production window — no reliability= argument needed:
from praisonaiagents import Agent
from praisonai_bot.bots.botos import BotOS
agent = Agent(name="support", instructions="Answer customer questions.")
bot = BotOS(
agent=agent,
platforms=["telegram", "discord", "slack"],
)
bot.start() # bound to a real interface → 15s drain + admission + fair queueExtend the drain window for slow agents
bot = BotOS(
agent=agent,
platforms=["telegram"],
reliability="production",
drain_timeout=45.0, # 45s instead of preset 15s
)Production preset with per-thread ordering
The production preset enables strict ordering; pass a custom lane_key to order sends within a shared channel:
from praisonaiagents import Agent
from praisonai.bots import BotOS
agent = Agent(name="support", instructions="Answer customer questions.")
bot = BotOS(agent=agent, platforms=["slack"], reliability="production")
# Later, when enqueuing on the outbox, group by thread:
await bot.outbox.enqueue(
idempotency_key=f"reply-{msg_id}",
target="slack:C0123456",
payload={"text": reply},
lane_key=f"slack:C0123456:thread:{thread_ts}",
)Disable all backpressure for development
reliability: offBest Practices
Recommended: pass nothing — the unset posture is now production-safe
On a non-loopback bind the unset posture is equivalent to production — same admission ceiling, fair queue, strict ordering, and 15 s drain. Most operators don’t need to pass anything. Use reliability="production" only to pin the 15 s window even on a loopback bind.
I want the pre-3438 behaviour back
Pass reliability="off" for no drain and no admission, or reliability="default" for a 5 s drain with no admission ceiling. Neither is a recommended default — they exist for callers who explicitly want the pre-#3438 shape.
Never mix reliability= with manual drain/admission in YAML unless intentional
Explicit YAML keys like gateway.drain_timeout override the preset. That is correct behaviour when you need to tune a single value, but it can surprise you if you forget the preset was set.
Unknown profile names raise immediately — do not catch the error
An unrecognised profile (e.g. reliability: "fast") raises at startup, not at first request. This fail-fast behaviour is intentional — silent fallback to default would hide misconfiguration.
Use –reliability CLI flag for canary deployments
Deploying a new preset to a single pod via the CLI flag lets you validate behaviour before updating the shared gateway.yaml.
Related
Bot gateway architecture and core concepts
Gateway Graceful DrainIn-flight turn drain on shutdown or reload
Gateway Admission ControlCap concurrent runs and queue overflow requests
Gateway Flow ControlBack-pressure and send-policy options
Outbound OrderingPer-conversation FIFO delivery the production preset turns on
Full-restart RollbackA structural reload validates the candidate first and restores the previous config if channels fail to start
Event-Loop WatchdogDetect a wedged asyncio loop — Python-first via GatewayConfig(watchdog=True)