Let messages-per-hour 0 turn the hourly pause off (issue 1476)
mesh/merge-gate head a5d3480e7e5d merged into trunk 59f8c9be0090 — pass: builds messenger → novox; no bus step; every machine composes with the change as i…
mesh/repo-check head a5d3480e7e5d merged into trunk 59f8c9be0090 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
mesh/merge-gate head a5d3480e7e5d merged into trunk 59f8c9be0090 — pass: builds messenger → novox; no bus step; every machine composes with the change as i…
mesh/repo-check head a5d3480e7e5d merged into trunk 59f8c9be0090 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
This commit is contained in:
@@ -34,10 +34,33 @@ func TestMessagesPerHourIsReadFromTheSettingsFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return readSettings(p)
|
return readSettings(p)
|
||||||
}
|
}
|
||||||
if s, err := read(`{"messages-per-hour": 100}`); err != nil || s.MessagesPerHour != 100 {
|
if s, err := read(`{"messages-per-hour": 100}`); err != nil || s.MessagesPerHour == nil || *s.MessagesPerHour != 100 {
|
||||||
t.Fatalf("set: %+v %v", s, err)
|
t.Fatalf("set: %+v %v", s, err)
|
||||||
}
|
}
|
||||||
if s, err := read(`{"time-zone": ""}`); err != nil || s.MessagesPerHour != 0 {
|
if s, err := read(`{"messages-per-hour": 0}`); err != nil || s.MessagesPerHour == nil || *s.MessagesPerHour != 0 {
|
||||||
|
t.Fatalf("zero: %+v %v", s, err)
|
||||||
|
}
|
||||||
|
if s, err := read(`{"time-zone": ""}`); err != nil || s.MessagesPerHour != nil {
|
||||||
t.Fatalf("unset: %+v %v", s, err)
|
t.Fatalf("unset: %+v %v", s, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0 turns the pause off (issue 1476): every message goes out and the pause is never said.
|
||||||
|
func TestACapOfZeroTurnsThePauseOff(t *testing.T) {
|
||||||
|
h, tg, _, c, _ := newHolder(t)
|
||||||
|
h.Desk = nil
|
||||||
|
h.CapPerHour = func() int { return 0 }
|
||||||
|
for i := 0; i < 500; i++ {
|
||||||
|
h.Condition(EventRaised, cond(fmt.Sprintf("machine.m%d.silent", i), Urgent, "a machine is silent"))
|
||||||
|
c.pass(BurstWindow + time.Second)
|
||||||
|
h.Flush()
|
||||||
|
}
|
||||||
|
if len(tg.sends) != 500 {
|
||||||
|
t.Fatalf("sent %d of 500", len(tg.sends))
|
||||||
|
}
|
||||||
|
for _, m := range tg.sends {
|
||||||
|
if strings.HasPrefix(m.Title, "Mesh messages paused") {
|
||||||
|
t.Fatalf("the pause was said with the cap off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -325,7 +325,7 @@ type Holder struct {
|
|||||||
// `only-what-needs-me`, ADR 0308 §4); nil, none is.
|
// `only-what-needs-me`, ADR 0308 §4); nil, none is.
|
||||||
NeedsOnly func(kind string) bool
|
NeedsOnly func(kind string) bool
|
||||||
// CapPerHour is the most messages one channel gets an hour (the setting messages-per-hour, issue 1476);
|
// CapPerHour is the most messages one channel gets an hour (the setting messages-per-hour, issue 1476);
|
||||||
// nil, or a value below one, is DefaultCapPerHour. TellCapPerHour is its own and stays fixed.
|
// nil, or a value below zero, is DefaultCapPerHour; 0 is no cap at all. TellCapPerHour is its own and stays fixed.
|
||||||
CapPerHour func() int
|
CapPerHour func() int
|
||||||
|
|
||||||
work sync.Mutex // one event, call or tick at a time
|
work sync.Mutex // one event, call or tick at a time
|
||||||
@@ -1212,10 +1212,10 @@ func withheldLine(line string, refusal Refusal, passes func(string) (Refusal, bo
|
|||||||
return "(a line carrying " + refusal.What + " is withheld here)"
|
return "(a line carrying " + refusal.What + " is withheld here)"
|
||||||
}
|
}
|
||||||
|
|
||||||
// capPerHour is the cap now in force on a channel's messages an hour.
|
// capPerHour is the cap now in force on a channel's messages an hour; 0 is none.
|
||||||
func (h *Holder) capPerHour() int {
|
func (h *Holder) capPerHour() int {
|
||||||
if h.CapPerHour != nil {
|
if h.CapPerHour != nil {
|
||||||
if n := h.CapPerHour(); n >= 1 {
|
if n := h.CapPerHour(); n >= 0 {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ type Settings struct {
|
|||||||
// with nothing held and nothing open is not told there at all (novox/hq ADR 0308 §4).
|
// with nothing held and nothing open is not told there at all (novox/hq ADR 0308 §4).
|
||||||
OnlyWhatNeedsMe []string `json:"only-what-needs-me"`
|
OnlyWhatNeedsMe []string `json:"only-what-needs-me"`
|
||||||
// MessagesPerHour is the most messages one channel gets in an hour (issue 1476); 0, not given, is
|
// MessagesPerHour is the most messages one channel gets in an hour (issue 1476); 0, not given, is
|
||||||
// DefaultCapPerHour.
|
// DefaultCapPerHour; 0 is no cap at all.
|
||||||
MessagesPerHour int `json:"messages-per-hour"`
|
MessagesPerHour *int `json:"messages-per-hour"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// zoneOf is the location a time-zone setting names, or this machine's own when it names none or one
|
// zoneOf is the location a time-zone setting names, or this machine's own when it names none or one
|
||||||
@@ -69,7 +69,11 @@ func readSettings(path string) (Settings, error) {
|
|||||||
switch v := loose["messages-per-hour"].(type) {
|
switch v := loose["messages-per-hour"].(type) {
|
||||||
case nil:
|
case nil:
|
||||||
case float64:
|
case float64:
|
||||||
s.MessagesPerHour = int(v)
|
n := int(v)
|
||||||
|
if v < 0 || v != float64(n) {
|
||||||
|
return s, fmt.Errorf("messages-per-hour is not a whole number of zero or more")
|
||||||
|
}
|
||||||
|
s.MessagesPerHour = &n
|
||||||
default:
|
default:
|
||||||
return s, fmt.Errorf("messages-per-hour is not a number")
|
return s, fmt.Errorf("messages-per-hour is not a number")
|
||||||
}
|
}
|
||||||
@@ -340,8 +344,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
return loc
|
return loc
|
||||||
},
|
},
|
||||||
Emit: func(event string, body any) error { return stdio.Emit(event, body) },
|
Emit: func(event string, body any) error { return stdio.Emit(event, body) },
|
||||||
CapPerHour: func() int { return settings().MessagesPerHour },
|
CapPerHour: func() int {
|
||||||
|
if n := settings().MessagesPerHour; n != nil {
|
||||||
|
return *n
|
||||||
|
}
|
||||||
|
return DefaultCapPerHour
|
||||||
|
},
|
||||||
NeedsOnly: func(kind string) bool {
|
NeedsOnly: func(kind string) bool {
|
||||||
for _, k := range settings().OnlyWhatNeedsMe {
|
for _, k := range settings().OnlyWhatNeedsMe {
|
||||||
if k == kind {
|
if k == kind {
|
||||||
|
|||||||
@@ -613,7 +613,8 @@ func (h *Holder) sendNow(ch Channel, key, what string, m Message) bool {
|
|||||||
// tell is not counted here: it has its own cap (TellCapPerHour) so a burst of tells cannot crowd
|
// tell is not counted here: it has its own cap (TellCapPerHour) so a burst of tells cannot crowd
|
||||||
// out a condition or an ask (ADR 0380 §8).
|
// out a condition or an ask (ADR 0380 §8).
|
||||||
func (h *Holder) allow(channel string) bool {
|
func (h *Holder) allow(channel string) bool {
|
||||||
return h.sentLastHour(channel) < h.capPerHour()
|
n := h.capPerHour()
|
||||||
|
return n == 0 || h.sentLastHour(channel) < n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Holder) sentLastHour(channel string) int {
|
func (h *Holder) sentLastHour(channel string) int {
|
||||||
|
|||||||
@@ -135,8 +135,8 @@
|
|||||||
},
|
},
|
||||||
"messages-per-hour": {
|
"messages-per-hour": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "The most messages the mesh sends one channel in an hour, in messages per channel per hour; past it the rest are held and said once as one message (not the tell verb, which has its own cap of 10).",
|
"description": "messages per channel per hour before the rest are held as one; 0 turns the pause off. The tell verb has its own cap of 10 and is not counted here.",
|
||||||
"minimum": 1,
|
"minimum": 0,
|
||||||
"maximum": 1000,
|
"maximum": 1000,
|
||||||
"trusted": false,
|
"trusted": false,
|
||||||
"default": 100
|
"default": 100
|
||||||
|
|||||||
Reference in New Issue
Block a user