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.
Ask a running gateway to finish in-flight turns and exit — without exposing any inbound port, and without a left-over signal wedging a restarted instance. The user drops a drain marker file; the gateway finishes in-flight turns and exits without exposing an inbound drain port.

Quick Start

1

Import the policy and epoch function

2

Build the policy once at startup

3

Run a watcher loop

The pattern above is for advanced Python embeddings. On the primary WebSocketGateway the watcher is built in — enable it with the lifecycle: block or --drain-marker flag below instead of writing your own loop.
4

Primary runtime — enable the built-in watcher via gateway.yaml

The primary WebSocketGateway (praisonai gateway start) ships a built-in marker watcher. Point it at a marker path with a lifecycle: block.
The gateway polls the marker every 5 seconds and, on an epoch match, drains active sessions bounded by the gateway’s drain_timeout.
5

Primary runtime — enable via CLI flag (no YAML)

The flag synthesizes the lifecycle.drain block, so CLI overrides win over gateway.yaml.
6

Trigger a drain from a deploy step


How It Works

Restart-Safety Story

The entire point of this feature: a marker stamped with current_epoch() is silently ignored by any other instance of the gateway — even if the marker file survives a reboot on a durable volume.

Decision Tree — When Is a Marker Honoured?


The Drain Marker Contract

Write this JSON to the marker path:
  • Default marker path (convention from PraisonAI #2390, not yet enforced in code): ~/.praisonai/gateway/.drain_request.json
  • action defaults to "drain" if absent. Any other value (including a non-string) is ignored.
  • Missing / empty / non-string epoch is ignored unless require_epoch=False is passed to the policy.

Configuration Options

DrainMarkerPolicy constructor

DrainMarkerPolicy.drain_requested() parameters

current_epoch() — what it returns

lifecycle.drain: YAML block (WebSocketGateway)

The primary WebSocketGateway reads the built-in watcher from a lifecycle: block at the top level of gateway.yaml or nested under gateway:.
The watcher polls every 5 seconds. On an epoch match it sets _draining = True and calls _drain_active_sessions(reason="drain-marker", timeout=drain_timeout), so the gateway’s existing drain_timeout bounds the marker-triggered drain.

Observability

When the built-in watcher runs, health() surfaces it under the lifecycle object:
drain_marker_watch is true while the watch loop is running. The lifecycle field appears only when a lifecycle feature is configured.

Common Patterns

1. Operator-side: write the marker

Writing to <path>.tmp then os.replace() makes the write atomic — a half-written JSON file is treated as malformed and ignored.

2. Gateway-side: minimal watcher loop

3. Accepting legacy markers without an epoch (advanced)

Only do this if you own both ends and have a different staleness story.

Best Practices

The whole restart-safety guarantee depends on it. Leave require_epoch=True (the default). An unstamped marker is silently ignored — this is intentional and protects newly started instances from stale files.
Write to <path>.tmp then os.replace() — a half-written JSON file is parsed as malformed and ignored, leaving the previous request still active. Atomic rename is the only safe pattern on most filesystems.
DrainMarkerPolicy only decides when to drain; the actual bounded wait still goes through gateway.stop(drain_timeout=...) documented on the Session Continuity page. Without a drain_timeout, shutdown cancels in-flight turns immediately.
The epoch is non-secret and opaque. Treat the marker file as world-readable convention metadata, not a control-plane secret. Anyone who can write to the marker path can trigger a drain.

The built-in marker watcher now ships on the primary WebSocketGateway — enable it with lifecycle.drain.marker_path or --drain-marker (PraisonAI #3021). A dedicated praisonai gateway drain marker-writer CLI is a separate follow-up; until it lands, write the marker with the atomic-write snippet above.

Scale to Zero

ScaleToZeroPolicy — sibling idle-policy predicate

Session Continuity

drain_timeout and in-process drain

Crash-Loop Guard

Sibling lifecycle policy — stop auto-resuming a crash-looping channel

Gateway

Gateway and Control Plane top-level page