Age a restricted stream's dead letters out with it and never show their body (issue 728)

DEAD_LETTERS kept a message given up on MAIL forever and showed it whole to any caller of dead-letters, outside the grant and past MAIL's week. Per ADR 0376 §3-§6: the kept copy carries a per-message time to live of what is left of its stream's age (a copy already past it is kept without its body), DEAD_LETTERS and EVENTS allow per-message TTL, the list and show give no body or own headers for it, delivering it again needs a minute left and the copy keeps the time left, and its max-deliveries condition clears saying how many aged out undelivered and from which stream.
This commit is contained in:
jochen
2026-10-15 14:11:37 +02:00
parent f75cd0239d
commit d03e24f423
10 changed files with 690 additions and 7 deletions
+15 -2
View File
@@ -59,8 +59,17 @@ type Stream struct {
// DuplicatesSeconds is the window in which a message id published twice is kept once; zero for the
// server's default (two minutes).
DuplicatesSeconds int
// AllowMsgTTL lets a message carry a time to live of its own (`Nats-TTL`), for what must not outlive the
// stream it came from (novox/hq ADR 0376 §3, §5).
AllowMsgTTL bool
// Restricted marks a module's stream restricted by a grant (novox/hq ADR 0363 §4), in the stream's own
// metadata, so whoever keeps one of its messages reads it from the bus (ADR 0376 §3).
Restricted bool
}
// RestrictedMetadata is the key a restricted stream's metadata says it under.
const RestrictedMetadata = "mesh-restricted"
// AssignmentsStream holds every assignment's membership, the newest per subject.
const AssignmentsStream = "ASSIGNMENTS"
@@ -174,6 +183,8 @@ func MeshStreams() []Stream {
Retention: RetentionLimits,
MaxAge: 7 * 24 * 60 * 60,
MaxMsgsPerSubject: 10000,
// A restricted dead letter delivered again keeps what is left of its stream's age (ADR 0376 §5).
AllowMsgTTL: true,
Why: "a subscriber that was down catches up; tool traffic under the same prefix is " +
"excluded by the event token; per-subject caps keep a noisy emitter from " +
"evicting a quiet one without splitting the stream",
@@ -194,9 +205,11 @@ func MeshStreams() []Stream {
MaxBytes: DeadLettersBytes,
DiscardNew: true,
DuplicatesSeconds: 24 * 60 * 60,
AllowMsgTTL: true,
Why: "every message a consumer gave up on, with its consumer, subject, deliveries and when, kept " +
"until a person delivers it again or drops it with why (novox/hq issue 330); no age, and full " +
"it refuses the next copy rather than drop one it holds",
"until a person delivers it again or drops it with why (novox/hq issue 330); no age but a restricted " +
"stream's message, which ages out with its stream (ADR 0376), and full it refuses the next copy " +
"rather than drop one it holds",
},
}
}