Skip to content

Add sse_retry and transient_retry: set the retry hints NUTS sends (#145) - #156

Merged
bpacholek merged 1 commit into
mainfrom
fix-145-retry-hints
Sep 27, 2026
Merged

bpacholek merged 1 commit into
mainfrom
fix-145-retry-hints

Conversation

@bpacholek

Copy link
Copy Markdown
Contributor

Summary

Two directives set the reconnection hints NUTS sends (#145):

  • sse_retry <milliseconds> sends retry: with every stream's handshake,
    just before the connected event. EventSource then waits that long after
    an ordinary disconnect (a dropped network, a reload, a write timeout)
    instead of the browser's default of a few seconds. 0, the default, sends
    none, as before.
  • transient_retry <seconds> sets the average of the jittered delay NUTS
    asks for in three places: the retry stream's retry:, Retry-After for
    clients that are not EventSource, and the retry: of the reset frame that
    ends a stream whose JetStream stream was recreated or rewound (Streams go silent when their stream is recreated under live connections #133,
    Send the recreated-stream reset as a reset event (#133 follow-up) #147). The delay stays jittered by ±50%; 0 or omitted keeps 5 seconds,
    so the defaults do not change.

Both accept up to an hour. The Caddyfile parser rejects negative values, and
validation rejects anything over an hour.

Docs: the README (directive list, a "Retry hints" section, the transient
failure text), docs/CONFIGURATION.md, docs/TROUBLESHOOTING.md, the
website's usage page and the CHANGELOG.

Tests

  • Unit tests:
    • the delay stays within ±50% of transient_retry (unset, 2 and 30),
      with both halves of the range reached;
    • the retry stream and Retry-After follow transient_retry, and so
      does the reset frame's retry:;
    • the connected event carries retry: with sse_retry;
    • Caddyfile rows: full config, missing arguments, values that are not
      numbers, negative values, over an hour, exactly an hour;
    • provision JSON rows, and the documented defaults.
  • Godog: "Streams set the reconnection delay" on /details, which
    Caddyfile.test now configures with sse_retry 2500.

Mutation testing

make mutate-pkg, no mutants lived in any file:

File Killed Lived Not covered
caddyfile.go 47 0 0
provision.go 219 0 16
serve.go 225 0 9

The not-covered mutants sit on constant declarations and tagless switch
cases, which gremlins cannot see. scripts/mutate-by-hand.py covered the
new ones, and 27 hand mutants were all killed. They targeted:

  • the 5 s default and the one-hour caps (off by one);
  • the unit and the fallback in retryDelay, and the width of its jitter;
  • the retry: line's format;
  • the delays rejectTransient and endGeneration send;
  • the Provision default and both halves of each validation check;
  • the Caddyfile assignments and the names in their errors;
  • the JSON tags.

In the first pass five of them lived. They are now killed by the tests for
exactly an hour, for values that are not numbers, for both halves of the
jitter, and for the reset frame's delay.

🤖 Generated with Claude Code

sse_retry <milliseconds> sends retry: with every stream's handshake, so
EventSource waits that long after an ordinary disconnect (a dropped
network, a reload, a write timeout) instead of the browser's default of a
few seconds. 0, the default, sends none.

transient_retry <seconds> sets the average of the jittered delay NUTS asks
for after a transient failure (the retry stream's retry:, Retry-After) and
in the reset frame of a stream whose JetStream stream was recreated or
rewound. It stays jittered by ±50%, and 5 seconds remains the default.

Both accept up to an hour.

Closes #145

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@bpacholek
bpacholek merged commit 0f471cd into main Sep 27, 2026
5 checks passed
@bpacholek
bpacholek deleted the fix-145-retry-hints branch September 27, 2026 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant