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.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 The gateway polls the marker every 5 seconds and, on an epoch match, drains active sessions bounded by the gateway’s
WebSocketGateway (praisonai gateway start) ships a built-in marker watcher. Point it at a marker path with a lifecycle: block.drain_timeout.5
Primary runtime — enable via CLI flag (no YAML)
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 withcurrent_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 actiondefaults to"drain"if absent. Any other value (including a non-string) is ignored.- Missing / empty / non-string
epochis ignored unlessrequire_epoch=Falseis 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
<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)
Best Practices
Always stamp markers with current_epoch()
Always stamp markers with current_epoch()
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 the marker atomically
Write the marker atomically
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.Pair with drain_timeout
Pair with drain_timeout
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.Don't store secrets in the marker
Don't store secrets in the marker
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.Related
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

