Skip to main content
Stop auto-resurrecting a channel that keeps crashing on resume, before it burns the process into a tight restart loop.

Quick Start

1

Simplest — enable via gateway.yaml

Defaults trip the breaker after 3 rapid restarts within 60 seconds for any channel.
2

Custom window

Trip only after 5 restarts inside a 2-minute window — more tolerant of transient flaps.
3

Python — build the pure guard

When the guard trips, the gateway logs the crash-loop-halted line and stops auto-resurrecting that channel.

How It Works

The guard runs around the channel supervisor loop. Each crashed boot is recorded; once the trailing window holds max_restarts events, the gateway stops resurrecting that channel.

Configuration Options

RestartLoopGuard constructor

Methods:

lifecycle.restart_loop_guard: YAML block

Accepted at the top level of gateway.yaml or nested under gateway:.

Imports

RestartLoopGuard exports from praisonaiagents.gateway. Top-level praisonaiagents does not re-export it.

How It Composes With Channel Supervision

The crash-loop guard is a rapid-fire breaker (seconds window) that runs around the supervisor loop. It is orthogonal to the Channel Supervision health-monitor machinery: Tune all three for a layered defence: the guard catches immediate crash storms per channel; max_restarts_per_hour catches slow, persistent flapping per channel; the fleet breaker catches a systemic fault that restarts every channel at once.

Log signal

When the guard trips, the gateway emits:

Fleet-level breaker

The per-channel guards above catch one bad channel. A systemic fault — a bad shared provider, a network partition, an org-wide expired token — restarts every channel at once, and each one silently burns its own max_restarts_per_hour budget in a fleet-wide reconnect storm. FleetSupervisionPolicy sits on top of the per-channel budgets and trips one operator-visible breaker instead.

FleetSupervisionPolicy — a pure aggregate breaker

FleetSupervisionPolicy is a pure, dependency-free, side-effect-free breaker — the aggregate sibling of RestartLoopGuard. Import it from praisonaiagents.gateway:
Validation. Out-of-range constructor values raise ValueErrorfleet_restarts_per_hour < 1, failing_channel_fraction outside (0.0, 1.0], or breaker_cooldown_s < 0.

Recovery

The breaker re-arms cleanly after breaker_cooldown_s — once cooldown elapses, tripped() clears the event window so pre-trip events cannot immediately re-trip it. When wired into the gateway, the degraded-owner fact (see below) clears on the next monitor sweep without an external get_status() poll: wait one breaker_cooldown_s after the underlying cause is fixed and the entry disappears on its own.

Observability

When wired into the gateway, get_status() / gateway status / /health gain a fleet block:
When the fleet breaker trips, the monitor records exactly one entry on the shared Degraded-Capability Registry: The log line on trip:
The fleet block and the degraded owner flow through health() / gateway status / gateway doctor automatically — WebSocketGateway constructs the supervisor with the shared degraded_registry, so there is nothing to wire. A None registry keeps supervision fully functional (the breaker still holds restarts); it is only silent on the aggregate degraded surface. The standalone single-channel Bot path is unaffected — a 1-channel fleet never false-trips.
FleetSupervisionPolicy is YAML-only + direct-Python configuration. It is not an Agent constructor parameter, and you never construct ChannelHealthMonitor yourself — the public Python surface is FleetSupervisionPolicy plus the gateway.health.* YAML keys. Tune the three keys on Channel Supervision › Restart guard-rails.

Best Practices

The defaults trip after 3 restarts within 60 seconds — a rate that only a genuine crash-on-resume loop hits. Change them only when a channel legitimately flaps (e.g. a flaky upstream) and you want more tolerance.
The guard is a fast breaker; max_restarts_per_hour on Channel Supervision is a slow per-hour cap. Enable both so a rapid crash storm is stopped in seconds and slow persistent flapping is stopped over the hour.
A trip means the channel stopped auto-resurrecting. Once the underlying crash is fixed, run praisonai gateway reconnect <channel> (see Channel Supervision → Reconnect) to reset error state and bring the channel back.
_count_failing_channels treats a channel as failing when its per-channel restart budget is exhausted (not can_restart). With max_restarts_per_hour = 0 (disabled), idle channels with no recorded restarts are not counted as failing — so a quiet fleet never false-trips the aggregate breaker. Lower failing_channel_fraction only when you want the breaker to fire before half the fleet is down.
Once you fix the systemic cause (rotate the shared token, heal the partition), the fleet breaker holds restarts for breaker_cooldown_s then re-arms on its own. The gateway/fleet degraded owner clears on the next monitor sweep — no external gateway status poll required.

Channel Supervision

Self-healing channels — the supervisor the guard wraps.

Gateway Exit Codes

Restart-intent exit codes that pair with crash forensics.

Scale to Zero

Sibling lifecycle policy — idle-quiesce for serverless hosts.

Drain Trigger

Sibling lifecycle policy — epoch-safe external drain marker.

Event-Loop Watchdog

Another source of EX_TEMPFAIL (75) — a wedged asyncio loop.