76 lines
4.1 KiB
Go
76 lines
4.1 KiB
Go
package views
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// The findings a views part writes in its own state `findings`, which the condition keeper raises and clears
|
|
// (novox/hq ADR 0564 §2): an owner's value too large for an event (TooLargeKind), an owner's change not said past its
|
|
// bound (UnsaidKind), and a reader's first view unanswered past its bound (UnansweredKind).
|
|
const (
|
|
TooLargeKind = "view-too-large"
|
|
UnsaidKind = "view-unsaid"
|
|
UnansweredKind = "first-view-unanswered"
|
|
)
|
|
|
|
// Finding is what a views part says is wrong with a state it owns or follows, in plain fields: Kind and ID name it (a module-scoped
|
|
// finding of the observer), Summary, Headline and Explanation say it. It carries no layout: the writer a part gives
|
|
// (FindingWriter) encodes it as the condition keeper reads it, which is the seat mesh-conditions' contract, not this
|
|
// package's (novox/hq ADR 0634 §4, ADR 0635 §4).
|
|
type Finding struct {
|
|
Observer string
|
|
Kind string
|
|
ID string
|
|
Summary string
|
|
Headline string
|
|
Explanation string
|
|
At time.Time
|
|
}
|
|
|
|
// FindingWriter writes and clears a part's findings in its own state `findings`, where the condition keeper raises and
|
|
// clears conditions from them (novox/hq ADR 0564 §2): the part gives the one that encodes a Finding as that state's layout.
|
|
type FindingWriter interface {
|
|
Put(f Finding) error
|
|
Delete(f Finding) error
|
|
}
|
|
|
|
// UnsaidFinding is the owner's finding of a change of state it has not said on its views family since since: every
|
|
// reader of the state stands still at the change before it until it is said, which clears this.
|
|
func UnsaidFinding(owner, state, key string, revision uint64, since time.Time, cause string, at time.Time) Finding {
|
|
id := owner + "." + state
|
|
summary := fmt.Sprintf("%s has not said the change of %s.%s at %d on its views family since %s (%s): its readers stand still before it",
|
|
owner, state, key, revision, since.UTC().Format(time.RFC3339), strings.TrimSpace(cause))
|
|
return finding(owner, UnsaidKind, id, summary,
|
|
fmt.Sprintf("%s cannot say a change of its %s", owner, state),
|
|
"The owner says each change of its state as an event on its own stream, and says a change again until the bus takes it; "+
|
|
"its readers hear nothing newer meanwhile. Look at the owner's stream on the bus: is it full, or is the bus away?", at)
|
|
}
|
|
|
|
// TooLargeFinding is the owner's finding of state's key too large to say whole on its views family.
|
|
func TooLargeFinding(owner, state, key string, size int, at time.Time) Finding {
|
|
id := owner + "." + state + "." + key
|
|
summary := fmt.Sprintf("%s's %s.%s holds %d bytes, more than one views event carries (%d): every reader asks its first view again at each change of it", owner, state, key, size, MaxValueBytes)
|
|
return finding(owner, TooLargeKind, id, summary,
|
|
fmt.Sprintf("A value of %s is too large for its views event", owner),
|
|
"Each change of this key is said as a gap, so every reader of the state asks the owner's first view once more. "+
|
|
"It works, but costs a first view per change; the value should be made smaller or split.", at)
|
|
}
|
|
|
|
// UnansweredFinding is a reader's finding of its first view of s unanswered past its bound (ADR 0615 §6): it names the
|
|
// owner and the tool. A first view answered at revision 0 with nothing in it is said too, with the operator's step.
|
|
func UnansweredFinding(reader string, s Status, at time.Time) Finding {
|
|
id := reader + "." + s.Owner + "." + s.State
|
|
summary := fmt.Sprintf("%s has no first view of %s's %s: %s has not answered since %s (%s)", reader, s.Owner, s.State, s.Tool,
|
|
s.Asked.Format(time.RFC3339), strings.TrimSpace(s.Error))
|
|
return finding(reader, UnansweredKind, id, summary,
|
|
fmt.Sprintf("%s waits for %s", reader, s.Owner),
|
|
fmt.Sprintf("%s reads %s's %s only through %s, and keeps asking it; it never reads the state itself. The answer clears this. "+
|
|
"Look at %s's runtime of its own: is it running and connected?", reader, s.Owner, s.State, s.Tool, s.Owner), at)
|
|
}
|
|
|
|
func finding(observer, kind, id, summary, headline, explanation string, at time.Time) Finding {
|
|
return Finding{Observer: observer, Kind: kind, ID: id, Summary: summary, Headline: headline, Explanation: explanation, At: at.UTC()}
|
|
}
|