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 built-in marker watcher and
praisonai gateway drain CLI are not yet merged — write your own watcher loop for now (pattern above). This page will be updated when the follow-up PR ships.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
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.
Related
Scale to Zero
ScaleToZeroPolicy — sibling idle-policy predicate
Session Continuity
drain_timeout and in-process drain
Bot Gateway
Bot Gateway overview
Gateway
Gateway and Control Plane top-level page

