You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: documentation/docs/getting-started/configuration.mdx
+44-2Lines changed: 44 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -526,11 +526,53 @@ The channel name for broadcasting messages.
526
526
527
527
For more information, see [running OPAL with Kafka](/tutorials/run_opal_with_kafka) and [running OPAL with Apache Pulsar](/tutorials/run_opal_with_pulsar).
Enable experimental fix for broadcast connection loss issues.
533
+
Reconnect the broadcaster reader on a backbone disconnect instead of dropping all client connections. Set to `False` to revert to the legacy (non-reconnecting) broadcaster.
534
+
535
+
#### OPAL_BROADCAST_RECONNECT_MAX_RETRIES
536
+
537
+
Default: `0`
538
+
539
+
Maximum consecutive broadcaster reconnect attempts before giving up and letting the worker restart (`0` = retry forever).
540
+
541
+
#### OPAL_BROADCAST_RECONNECT_BACKOFF_MIN_SECONDS
542
+
543
+
Default: `0.5`
544
+
545
+
Minimum backoff in seconds between broadcaster reconnect attempts.
546
+
547
+
#### OPAL_BROADCAST_RECONNECT_BACKOFF_MAX_SECONDS
548
+
549
+
Default: `30.0`
550
+
551
+
Maximum backoff in seconds between broadcaster reconnect attempts.
552
+
553
+
#### OPAL_BROADCAST_REPLAY_BUFFER_SIZE
554
+
555
+
Default: `10000`
556
+
557
+
Maximum number of outbound broadcasts buffered while the backbone is down and replayed on reconnect (`0` disables buffering).
558
+
559
+
#### OPAL_BROADCAST_RESYNC_ON_RECONNECT
560
+
561
+
Default: `True`
562
+
563
+
After a backbone gap that may have lost updates, force this worker's connected clients to reconnect so they re-fetch full policy + data state (guarantees cross-instance consistency).
564
+
565
+
#### OPAL_BROADCAST_RESYNC_SETTLE_SECONDS
566
+
567
+
Default: `2.0`
568
+
569
+
Grace period after a broadcaster reconnect before replaying buffered broadcasts and resyncing clients, to let peer servers re-subscribe.
570
+
571
+
#### OPAL_BROADCAST_HEALTHCHECK_ENABLED
572
+
573
+
Default: `True`
574
+
575
+
Make `/healthcheck` reflect the broadcaster reader's health, so a Kubernetes readiness/liveness probe can route away from or restart a worker whose reader is wedged while clients depend on it.
| UVICORN_NUM_WORKERS | the number of workers in a single container (example value: `4`) |
62
+
63
+
#### 4) Broadcaster reconnection (resilience)
64
+
65
+
If the broadcast backbone (Postgres/Redis/Kafka) briefly drops — for example during a managed-database failover or restart — OPAL servers reconnect to it automatically with bounded exponential backoff, instead of dropping their connected clients. This is enabled by default; the following **server-side** env vars (all prefixed with `OPAL_`) tune it:
| OPAL_BROADCAST_RECONNECT_ENABLED |`true`| Reconnect the broadcaster reader on a backbone disconnect instead of dropping all client connections. Set to `false` for the legacy behavior. |
70
+
| OPAL_BROADCAST_RECONNECT_MAX_RETRIES |`0`| Maximum consecutive reconnect attempts before giving up and letting the worker restart. `0` means retry forever. |
71
+
| OPAL_BROADCAST_RECONNECT_BACKOFF_MIN_SECONDS |`0.5`| Minimum backoff (seconds) between reconnect attempts. |
72
+
| OPAL_BROADCAST_RECONNECT_BACKOFF_MAX_SECONDS |`30`| Maximum backoff (seconds) between reconnect attempts. |
73
+
| OPAL_BROADCAST_REPLAY_BUFFER_SIZE |`10000`| Max number of outbound broadcasts buffered while the backbone is down and replayed on reconnect (`0` disables buffering). On overflow the oldest are dropped. |
74
+
| OPAL_BROADCAST_RESYNC_ON_RECONNECT |`true`| After a backbone gap, force this worker's clients to reconnect so they re-fetch full policy + data state. Set to `false` to rely only on best-effort replay. |
75
+
| OPAL_BROADCAST_RESYNC_SETTLE_SECONDS |`2`| Grace period after a reconnect before replaying buffered broadcasts and resyncing clients, to let peer servers re-subscribe. |
76
+
| OPAL_BROADCAST_HEALTHCHECK_ENABLED |`true`| Make `/healthcheck` reflect the broadcaster reader's health: it returns `503` (instead of `200`) when the reader is wedged while clients depend on it, so a k8s readiness/liveness probe can route away from or restart the worker. A normal transient reconnect still reads healthy. Set to `false` to keep `/healthcheck` always `200`. |
77
+
78
+
Consistency across the outage is handled in two layers. While the backbone is unreachable, client websocket connections are kept alive but cross-server fan-out is paused. On reconnect:
79
+
80
+
-**Replay buffer** — broadcasts that failed to reach the backbone during the outage are replayed, so peer servers that have re-subscribed catch up without a client refetch. This is best-effort: the backbone keeps no replay of its own, so a peer that is slow to re-subscribe may miss a replayed message.
81
+
-**Resync** (the guarantee) — each server forces its own clients to reconnect and re-fetch the full policy/data state. Because every server experienced the same gap, every server reconciles its own clients and the fleet converges to current truth. Updates missed during the gap are therefore reconciled even if the replay did not reach a peer in time.
82
+
83
+
**Scope of the resync guarantee.** The resync re-fetch covers the policy and the **configured data sources** (those in `OPAL_DATA_CONFIG_SOURCES` / the server's data-source config) — clients fully refetch them. Runtime-published **incremental** updates — for example a `POST /data/config` that carries an inline `data` payload or a one-off fetch URL that is not part of the configured sources — are **not** part of that full refetch, so they are recoverable **only** through the best-effort replay buffer; if their replay is dropped (buffer overflow, or a peer that did not re-subscribe in time) the update is lost and not reconciled by the resync.
84
+
85
+
**Replay ordering.** Cross-worker replay ordering is not enforced, so a buffered update can be delivered after a newer live update (this self-heals for fetch-URL entries, which re-fetch current state, but a stale value can win for inline-`data` entries that carry the value directly).
0 commit comments