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.

python
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"],
)
Diagram

None

production

default

off

loopback / localhost / 127.x / ::1

0.0.0.0 / real interface / hostname

reliability=

bind_host

15s drain + admission + fair queue + strict

5s drain, no admission, best-effort

0s drain, no admission, best-effort

5s drain + admission + fair queue + strict

15s drain + admission + fair queue + strict

Quick Start

  1. 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()
  2. 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
    )
  3. YAML (gateway.yaml)
    yaml
    reliability: production
    # or nested under gateway:
    gateway:
      reliability: production
      max_concurrent_runs: 8   # explicit override still respected
  4. CLI
    bash
    praisonai gateway start --config gateway.yaml --reliability production

Profiles

Four distinct postures — the unset posture is bind-aware, so it appears twice.

PresetDrainAdmission ceilingWait queueOutbound orderingWhen to use
Unset (reliability=None, loopback bind)5 sYes (CPU-scaled)Yes (bounded, fair)strictLocal dev on 127.0.0.1 / localhost — safe by default
Unset (reliability=None, non-loopback bind)15 sYes (CPU-scaled)Yes (bounded, fair)strictAn actual deployment (0.0.0.0, real hostname) — full production posture is auto-picked
"production" (explicit)15 sYes (CPU-scaled)Yes (bounded, fair)strictExplicitly ask for the production window regardless of bind
"default" (explicit)5 sNoNobest-effortLegacy behaviour — you know what you’re doing and want the pre-#3438 shape
"off"0 sNoNobest-effortExplicit opt-out — immediate teardown, no backpressure. This is now the only way to get the pre-safe behaviour

What Each Knob Does

Diagram
ShutdownAgent RunnerAdmission GateInbound TurnShutdownAgent RunnerAdmission GateInbound Turnalt[under ceiling][at ceiling, queue_depth > 0][queue full]arrivescheck concurrent ceiling (production: CPU-scaled)dispatch immediatelywait in bounded queue (max 32)dispatch when slot opensreject (503-equivalent)drain(15s) — wait for in-flight turnsturns finish

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 default

Example — preset sets drain to 15s, but explicit override wins:

python
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.

Diagram

No — just run it

Force 15s drain on loopback too

Want pre-#3438 no-backpressure

Want legacy 5s-drain-no-ceiling

Need a specific
posture?

Leave reliability unset
(safe by default, bind-aware)

reliability=production

reliability=off

reliability=default


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.

Diagram
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