Let a module stream declare work-queue retention (issue 1177)

This commit is contained in:
jochen
2026-10-19 02:11:05 +02:00
parent ffad53aad2
commit a069898c0c
6 changed files with 206 additions and 3 deletions
@@ -0,0 +1,38 @@
package broker
import "testing"
// mailSendsStream is mesh-mail's future `mail-sends` stream (novox/hq ADR 0436 §7, §8), as the bus holds it:
// work-queue retention, a 24-hour duplicate window, kept one day and at most 64 MiB.
var mailSendsStream = ModuleStream{Module: "mesh-mail", Name: "MAIL_SENDS",
Events: []string{"mail.send.approved"}, MaxAgeDays: 1, MaxMiB: 64, WorkQueue: true, Duplicates: 24}
// 1177/AC1: a work-queue stream is composed with work-queue retention, refusing a new message when full
// (DiscardNew), a 24-hour duplicate window, a one-day maximum age and a 64 MiB cap.
func TestAWorkQueueStreamIsComposedToRefuseWhenFull(t *testing.T) {
s := mailSendsStream.Stream()
if s.Retention != RetentionWorkQueue {
t.Fatalf("retention: %v, want %v", s.Retention, RetentionWorkQueue)
}
if !s.DiscardNew {
t.Fatal("a work-queue stream did not refuse a new message when full")
}
if s.DuplicatesSeconds != 24*60*60 {
t.Fatalf("duplicate window: %d seconds, want %d (24 hours)", s.DuplicatesSeconds, 24*60*60)
}
if s.MaxAge != 24*60*60 {
t.Fatalf("max age: %d seconds, want %d (1 day)", s.MaxAge, 24*60*60)
}
if s.MaxBytes != 64<<20 {
t.Fatalf("max bytes: %d, want %d (64 MiB)", s.MaxBytes, 64<<20)
}
}
// 1177/AC3: a stream with no work-queue clause composes exactly as main does: limits retention, dropping its
// oldest, never refusing a new message.
func TestANonWorkQueueStreamStillDropsItsOldest(t *testing.T) {
s := mailStream.Stream()
if s.Retention != RetentionLimits || s.DiscardNew || s.DuplicatesSeconds != 0 {
t.Fatalf("composed as %+v; want limits retention, never discarding new, no duplicate window", s)
}
}
+17 -1
View File
@@ -49,6 +49,12 @@ type ModuleStream struct {
MaxMiB int
// Restricted says a trusted config value of the module grants who hears it (ADR 0363 §4).
Restricted bool
// WorkQueue says this stream holds ADR 0436 §6's work-queue retention: a message is removed once a
// consumer acknowledges it, and the bus refuses a new one when full rather than dropping its oldest.
WorkQueue bool
// Duplicates is the work-queue's duplicate window in hours (novox/hq ADR 0436 §6); meaningless unless
// WorkQueue.
Duplicates int
}
// Subjects are the subjects the stream takes.
@@ -70,7 +76,11 @@ func (s ModuleStream) Stream() Stream {
if s.Restricted {
why += "; heard only by the consumers its trusted config value grants"
}
return Stream{
if s.WorkQueue {
why += "; a work-queue (novox/hq ADR 0436 §6): a message is removed once its one consumer " +
"acknowledges it, and a full stream refuses a new one rather than dropping what it holds"
}
out := Stream{
Name: s.Name,
Subjects: s.Subjects(),
Retention: RetentionLimits,
@@ -80,6 +90,12 @@ func (s ModuleStream) Stream() Stream {
// Said on the bus, so a dead letter kept from it ages out with it (novox/hq ADR 0376 §3).
Restricted: s.Restricted,
}
if s.WorkQueue {
out.Retention = RetentionWorkQueue
out.DiscardNew = true
out.DuplicatesSeconds = s.Duplicates * 60 * 60
}
return out
}
// ModuleStreams is every declared module stream as the controller asserts it, in name order.