Skip to main content
The gateway now ships in the praisonai-bot package. praisonai serve gateway still works exactly as documented here; for a standalone install see praisonai-bot Migration.
For the composed one-switch experience, see Reliability Preset. This page documents the drain-only knob.
When a gateway process receives SIGTERM or SIGINT, it can wait for in-flight bot turns to complete before exiting — instead of cutting them off mid-response. Configure the drain window via the CLI, YAML, or Python.
The user sends SIGTERM to the gateway process; graceful drain stops new work and waits for in-flight bot turns up to drain_timeout.

Quick Start

1

Enable via the CLI flag

The gateway waits up to 30 seconds for in-flight turns to complete before exiting.
2

Enable via YAML config

3

Enable via Python

4

Override drain timeout at stop time

You can also pass a one-off timeout when stopping programmatically:
5

Enable via GatewayConfig (Python-first)

Set drain_timeout on GatewayConfig directly — no CLI flag and no YAML key required. This closes the CLI + YAML + Python parity gap for embedders wiring up a gateway from Python.
drain_timeout must be >= 0 (ValueError otherwise); 0/None disables the drain window.
6

Bound a wedged teardown with a diagnostic deadline

stop() also accepts a grace budget — extra seconds beyond drain_timeout before the shutdown-phase deadline watchdog fires a diagnosable self-exit if teardown itself is wedged (adapter disconnect(), WS drain, ledger/DB close). Requires the loop watchdog to be configured; a no-op otherwise.
Full mechanism and YAML config on the Loop Watchdog → Shutdown-phase deadline mode page.

How It Works

The drain phase uses DrainTimeoutPolicy from praisonaiagents.gateway.protocols. If the timeout elapses before all turns finish, the process exits forcefully but still attempts to flush any queued outbound messages.

Behaviour Table


Configuration Precedence

When multiple sources specify drain_timeout, the most specific wins: The GatewayConfig(drain_timeout=…) field is consulted only when there is no CLI flag and no YAML key. The start_with_config fallback checks "drain_timeout" not in gw_cfg before reading the field, so an explicit drain_timeout: null in YAML wins over the field. When drain_timeout is 0, the gateway exits immediately on SIGTERM without draining. When drain_timeout is None (and no reliability preset is set), a 5-second drain window is applied by the default posture — use reliability="off" to restore immediate-teardown behaviour.
Want to turn on graceful drain with a single switch alongside inbound admission control? See Gateway Reliability Presets.

Best Practices

Container orchestrators send SIGTERM before force-killing a pod. Set drain_timeout to slightly less than the terminationGracePeriodSeconds in your pod spec:
This gives the gateway 50 seconds to finish turns and 10 seconds of buffer for the process to exit cleanly.
If your agent typically responds in 5 seconds and your P99 is 20 seconds, set drain_timeout: 25. A timeout much larger than your P99 adds unnecessary shutdown delay without benefit.
drain_timeout bounds how long the gateway waits for in-flight turns; it does not bound how long a wedged teardown step (adapter disconnect(), WebSocket drain, ledger/DB close) can hang after the wait window ends. For that, enable the loop watchdog and set gateway.watchdog.shutdown_grace (or pass grace=… to stop()) — a wedged teardown then self-exits with an all-thread stack dump and exit code 75 at drain_timeout + shutdown_grace, instead of sitting silent until systemd’s TimeoutStopSec reaches SIGKILL. Added in PR #5084 / issue #5079. See Loop Watchdog → Shutdown-phase deadline mode.

Gateway Scale to Zero

Scale the gateway down when idle and back up on demand

Gateway Drain Trigger

Port-less external drain signal for hosted deployments
Detect a wedged loop and bound a wedged shutdown with a diagnostic self-exit.
The front-rung sibling — bound a wedged pre-loop startup with the same diagnostic self-exit.