diff --git a/evolution/proposals/ECP-0073-archive-relay-affinity-override.md b/evolution/proposals/ECP-0073-archive-relay-affinity-override.md new file mode 100644 index 0000000..d945432 --- /dev/null +++ b/evolution/proposals/ECP-0073-archive-relay-affinity-override.md @@ -0,0 +1,33 @@ +# ECP-0073: Archive Relay Affinity Override + +## Context + +`wt-archive` workers discover streams from `/api/public-streams` and subscribe to the listed `relay_url`. In practice, `cdn.moq.dev` resolves to region-local relay IPs, and broadcasts published from one region are not consistently visible from another region endpoint. + +For archive nodes running in a different region than publishers, this causes workers to connect successfully but wait indefinitely for broadcast announcements. + +## Decision + +Add an explicit Nix module option: + +- `services.every-channel.ec-node.archive.relayUrlOverride` (nullable string) + +When set, archive workers ignore per-entry `relay_url` from directory listings and always subscribe through the configured override URL. + +This allows operators to pin archive ingestion to the same relay endpoint used by publishers without changing public directory payloads. + +## Why + +- Restores deterministic archival ingestion across regions. +- Keeps deployment-level control in Nix (no app-level migration needed). +- Reversible with a single config change. + +## Rollout + +1. Set `archive.relayUrlOverride` on archive hosts that need relay affinity. +2. If override uses an IP literal, enable `archive.tlsDisableVerify = true` until SNI-preserving IP overrides are implemented. +3. Rebuild host and verify manifest growth. + +## Reversibility + +Unset `archive.relayUrlOverride` to return to directory-provided `relay_url` behavior. diff --git a/nix/modules/ec-node.nix b/nix/modules/ec-node.nix index c69eecc..c13bf0f 100644 --- a/nix/modules/ec-node.nix +++ b/nix/modules/ec-node.nix @@ -222,6 +222,12 @@ in description = "Discovery poll interval for public streams."; }; + relayUrlOverride = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = "Optional fixed relay URL override for archive workers (bypasses per-stream relay_url from directory entries)."; + }; + streamPrefix = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; @@ -669,6 +675,7 @@ in output_dir=${lib.escapeShellArg cfg.archive.outputDir} manifest_dir=${lib.escapeShellArg cfg.archive.manifestDir} relay_fallback=${lib.escapeShellArg cfg.relayUrl} + relay_override=${lib.escapeShellArg (if cfg.archive.relayUrlOverride == null then "" else cfg.archive.relayUrlOverride)} stream_prefix=${lib.escapeShellArg archivePrefix} state_dir="/run/every-channel/archive" pids_dir="$state_dir/pids" @@ -705,7 +712,9 @@ in if [[ -n "$stream_prefix" && "$name" != "$stream_prefix"* ]]; then continue fi - if [[ -z "$relay" ]]; then + if [[ -n "$relay_override" ]]; then + relay="$relay_override" + elif [[ -z "$relay" ]]; then relay="$relay_fallback" fi