Make the settle after a delivered walk a setting, two minutes by default (ADR 0505 §3)
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The tests of novox/hq ADR 0505 "How it is checked" for the router: what a delivery changes is held until it has
|
||||
// settled, every problem message says whether a delivery ran, and a failed delivery is told at once.
|
||||
|
||||
// ADR 0505 §3: the settle is a setting, settle-seconds, two minutes when none is given.
|
||||
func TestTheSettleIsReadFromTheSettingsFileAndIsTwoMinutesByDefault(t *testing.T) {
|
||||
read := func(body string) Settings {
|
||||
p := filepath.Join(t.TempDir(), "settings.json")
|
||||
if err := os.WriteFile(p, []byte(body), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s, err := readSettings(p)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
if s := read(`{"settle-seconds": 60}`); s.SettleSeconds == nil || *s.SettleSeconds != 60 {
|
||||
t.Fatalf("set: %+v", s)
|
||||
}
|
||||
if s := read(`{"time-zone": ""}`); s.SettleSeconds != nil {
|
||||
t.Fatalf("unset: %+v", s)
|
||||
}
|
||||
h := &Holder{}
|
||||
if got := h.settle(); got != 2*time.Minute {
|
||||
t.Fatalf("no setting: settle %s, want 2m", got)
|
||||
}
|
||||
h.Settle = func() time.Duration { return time.Minute }
|
||||
if got := h.settle(); got != time.Minute {
|
||||
t.Fatalf("a setting of 60 s: settle %s, want 1m", got)
|
||||
}
|
||||
h.Settle = func() time.Duration { return 0 }
|
||||
if got := h.settle(); got != 0 {
|
||||
t.Fatalf("a setting of 0: settle %s, want none", got)
|
||||
}
|
||||
}
|
||||
@@ -327,6 +327,9 @@ type Holder struct {
|
||||
// CapPerHour is the most messages one channel gets an hour (the setting messages-per-hour, issue 1476);
|
||||
// nil, or a value below zero, is DefaultCapPerHour; 0 is no cap at all. TellCapPerHour is its own and stays fixed.
|
||||
CapPerHour func() int
|
||||
// Settle is how long a delivered walk holds what it touched after its end (the setting settle-seconds, novox/hq
|
||||
// ADR 0505 §3); nil is DefaultSettle.
|
||||
Settle func() time.Duration
|
||||
|
||||
work sync.Mutex // one event, call or tick at a time
|
||||
mu sync.Mutex // what the status reads
|
||||
|
||||
@@ -35,6 +35,9 @@ type Settings struct {
|
||||
// MessagesPerHour is the most messages one channel gets in an hour (issue 1476); 0, not given, is
|
||||
// DefaultCapPerHour; 0 is no cap at all.
|
||||
MessagesPerHour *int `json:"messages-per-hour"`
|
||||
// SettleSeconds is how long a delivered walk still holds what it touched after its end (novox/hq ADR 0505 §3):
|
||||
// nil, not given, is DefaultSettle; 0 holds nothing after the end.
|
||||
SettleSeconds *int `json:"settle-seconds"`
|
||||
}
|
||||
|
||||
// zoneOf is the location a time-zone setting names, or this machine's own when it names none or one
|
||||
@@ -90,6 +93,17 @@ func readSettings(path string) (Settings, error) {
|
||||
default:
|
||||
return s, fmt.Errorf("only-what-needs-me is not a list of channel kinds")
|
||||
}
|
||||
switch v := loose["settle-seconds"].(type) {
|
||||
case nil:
|
||||
case float64:
|
||||
n := int(v)
|
||||
if v < 0 || v != float64(n) {
|
||||
return s, fmt.Errorf("settle-seconds is not a whole number of zero or more")
|
||||
}
|
||||
s.SettleSeconds = &n
|
||||
default:
|
||||
return s, fmt.Errorf("settle-seconds is not a number")
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
@@ -351,6 +365,12 @@ func main() {
|
||||
}
|
||||
return DefaultCapPerHour
|
||||
},
|
||||
Settle: func() time.Duration {
|
||||
if n := settings().SettleSeconds; n != nil && *n >= 0 {
|
||||
return time.Duration(*n) * time.Second
|
||||
}
|
||||
return DefaultSettle
|
||||
},
|
||||
NeedsOnly: func(kind string) bool {
|
||||
for _, k := range settings().OnlyWhatNeedsMe {
|
||||
if k == kind {
|
||||
|
||||
@@ -68,6 +68,9 @@ const (
|
||||
// DefaultWalkBound is a walk's bound when the controller gives none: the bound of a walk none of whose
|
||||
// deliveries has a budget (ADR 0308 §5).
|
||||
DefaultWalkBound = 15 * time.Minute
|
||||
// DefaultSettle is how long a delivered walk still holds what it touched after its end when the setting
|
||||
// settle-seconds gives none: the longest the first-node gate holds a healthy module (novox/hq ADR 0505 §3, ADR 0352).
|
||||
DefaultSettle = 2 * time.Minute
|
||||
// WalkForget: a walk whose end never came is forgotten this long after it started.
|
||||
WalkForget = 24 * time.Hour
|
||||
// WalkEndWhat is the outbox's name for a walk's end or bound message: it goes alone, never in a digest.
|
||||
@@ -76,6 +79,17 @@ const (
|
||||
MostNamed = 6
|
||||
)
|
||||
|
||||
// settle is how long a delivered walk still holds after its end (ADR 0505 §3).
|
||||
func (h *Holder) settle() time.Duration {
|
||||
if h.Settle == nil {
|
||||
return DefaultSettle
|
||||
}
|
||||
if d := h.Settle(); d >= 0 {
|
||||
return d
|
||||
}
|
||||
return DefaultSettle
|
||||
}
|
||||
|
||||
// Touch is what a walk moves on one machine.
|
||||
type Touch struct {
|
||||
Machine string `json:"machine"`
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"time-zone": "",
|
||||
"only-what-needs-me": [],
|
||||
"messages-per-hour": 100
|
||||
"messages-per-hour": 100,
|
||||
"settle-seconds": 120
|
||||
}
|
||||
|
||||
@@ -140,6 +140,14 @@
|
||||
"maximum": 1000,
|
||||
"trusted": false,
|
||||
"default": 100
|
||||
},
|
||||
"settle-seconds": {
|
||||
"type": "number",
|
||||
"description": "seconds a delivery that ended well still holds the messages about what it changed, so a problem that passes as the delivery settles is not sent (ADR 0505 §3); 0 holds nothing after the end.",
|
||||
"minimum": 0,
|
||||
"maximum": 3600,
|
||||
"trusted": false,
|
||||
"default": 120
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
@@ -163,7 +171,7 @@
|
||||
"type": "file",
|
||||
"path": "${dir:state}/settings.json",
|
||||
"mode": "0600",
|
||||
"takes-config": ["time-zone", "desktop-machines", "only-what-needs-me", "messages-per-hour"],
|
||||
"takes-config": ["time-zone", "desktop-machines", "only-what-needs-me", "messages-per-hour", "settle-seconds"],
|
||||
"merge": "json",
|
||||
"template": "files/settings.json",
|
||||
"owner": "messenger"
|
||||
|
||||
Reference in New Issue
Block a user