From 09d502ea3482cb8414f3f0a8271f201de9264ff0 Mon Sep 17 00:00:00 2001 From: atlas Date: Sat, 12 Sep 2026 21:16:28 +0200 Subject: [PATCH] swarm-nats: set max_payload to 8 MiB explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The swarm queue's rendered settings never named max_payload, so it ran on nats-server's upstream default of 1 MiB. That default is about to be too small: the broker is going to carry agent terminal rows (whole TermMsg bodies) published as complete messages rather than split, and a publish over the limit does not truncate — the server answers -ERR 'Maximum Payload Violation' and closes the connection, dropping the row. Set max_payload = 8388608 explicitly in the settings merge, with a comment on what it bounds and what bounds it (max_pending, which nats-server refuses to start past). Add a module-eval case that reads the rendered container config so a future edit that drops or shadows the key fails eval instead of surfacing as a dropped row in production. Refs #3805 --- nix/host-modules/swarm-nats.nix | 12 ++++++++++++ nix/module-eval.nix | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/nix/host-modules/swarm-nats.nix b/nix/host-modules/swarm-nats.nix index 4aef2a49..341ebb6a 100644 --- a/nix/host-modules/swarm-nats.nix +++ b/nix/host-modules/swarm-nats.nix @@ -674,6 +674,18 @@ in issuerKey = deployCfg.nats.calloutIssuerPublicKey; } // { + # The most a single publish may be, in bytes, before the + # server answers `-ERR 'Maximum Payload Violation'` and + # closes the connection — not a truncation, a dropped row + # and a reconnect. This queue is about to carry agent + # terminal rows published whole rather than split, so + # upstream's own default is sized to lose one of those + # rather than merely shorten it. Bounded from above by + # `max_pending`: nats-server refuses to start once this + # exceeds it, and widening that ceiling instead costs + # memory per connection, so this stays comfortably under it. + max_payload = 8388608; + # The monitoring endpoint, which is what the exporter below # reads. `//` adds a key `calloutBlocks` does not produce # (`accounts`, `authorization`) — checked, because a shallow diff --git a/nix/module-eval.nix b/nix/module-eval.nix index feb30d67..052226cf 100644 --- a/nix/module-eval.nix +++ b/nix/module-eval.nix @@ -752,6 +752,17 @@ let units ? swarm-nats-auth-secrets && lib.hasInfix "/run/secrets/nats-user.seed" units.swarm-nats-auth-secrets.script; } + { + # Reads the RENDERED settings, not the option: `calloutBlocks {…} // { + # … }` is a shallow merge, and a future edit that dropped or shadowed + # this key would still evaluate cleanly — the only reader that would + # notice is a publisher whose row exceeds upstream's much smaller + # default, and by then it is a dropped row, not an eval failure. + # Piggybacks on the pre-rename nats fixture above, which already + # renders this container's full config. + name = "the queue's payload ceiling is set, not inherited from the server's default"; + ok = natsOldPath.containers.swarm-nats.config.services.nats.settings.max_payload == 8388608; + } { # Reads the host's tmpfiles rules, not the options: the socket directory # nginx and the container share is created there, so a rename that