Files
mesh-catalog/modules/messenger/cmd/messenger/deliveryline.go
T

79 lines
2.9 KiB
Go

package main
// The delivery line (novox/hq ADR 0505 §1): every message about a problem — a condition or a module's notice,
// raised, asked, reopened, escalated or reminded — ends, after its since-when line, with whether a delivery was
// running on what it is about:
//
// - "During the delivery of <modules> to <machines>." when an open walk touches its subject;
// - "<n> after the delivery of <modules> to <machines>, which <outcome>." when a walk that touched it ended within
// its settle (a delivered walk settling, a failed or stopped one in the two minutes after it, §6);
// - "No delivery running." otherwise.
//
// The line is this router's, from the walks it keeps (ADR 0308 §1); no producer adds it. It names modules and
// machines as the operator says them, never an id, and is judged by the content rule with the rest of the body.
import (
"sort"
"time"
)
// NoDeliveryLine is the delivery line of a message no walk touches.
const NoDeliveryLine = "No delivery running."
// outcomeWords are a walk's outcome as the delivery line says it.
var outcomeWords = map[string]string{WalkDelivered: "succeeded", WalkFailed: "failed", WalkStopped: "was stopped"}
// carriesDeliveryLine says whether a message of a record says the delivery line: a problem's message, and not its
// clearing, its silencing, a plain notice or an ask's own message.
func carriesDeliveryLine(r *Record, what string) bool {
switch what {
case "cleared", "silenced", "tell":
return false
}
return r.Origin != "ask"
}
// deliveryLine is the line for a record's message at a moment.
func (h *Holder) deliveryLine(r *Record, now time.Time) string {
s := subjectOf(r)
h.mu.Lock()
defer h.mu.Unlock()
h.init()
var during, after []*Walk
for _, w := range h.walks {
if !w.touches(s) {
continue
}
switch {
case w.settling() && now.Before(w.SettleUntil) && !now.Before(w.Ended):
after = append(after, w)
case !w.settling():
during = append(during, w) // open, within its bound or past it (ADR 0505 §7)
}
}
if len(during) > 0 {
sort.Slice(during, func(i, j int) bool { return during[i].Started.Before(during[j].Started) })
return plainly("During the delivery of "+deliveryWords(during[0].Touches)+".", "During a delivery.")
}
if f := h.failedJustNow(s, now); f != nil {
after = append(after, f)
}
if len(after) == 0 {
return NoDeliveryLine
}
sort.Slice(after, func(i, j int) bool { return after[i].Ended.After(after[j].Ended) })
w := after[0]
ago := roughly(now.Sub(w.Ended))
return plainly(ago+" after the delivery of "+deliveryWords(w.Touches)+", which "+outcomeWords[w.Outcome]+".",
ago+" after a delivery, which "+outcomeWords[w.Outcome]+".")
}
// plainly is a line when the content rule lets it leave the mesh, else the same said without the names that it
// refused, so the line never withholds the message it ends.
func plainly(line, without string) string {
if _, ok := Check(line); ok {
return line
}
return without
}