mesh/delivery merged: source.main moved to novox/mesh-sdk@db26f7e8b6f5
mesh/check pass d4ae4b6790b8 on db26f7e8b6f5 | unit 1102 run, 680 kept, 2 skipped | integration 1103 run, 722 kept, 2 skipped | over bound: unit (slow…
149 lines
5.3 KiB
Go
149 lines
5.3 KiB
Go
package delivery
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// A put (novox/hq ADR 0546): one version of a module put on one node by the assigner's tool `assigner_put`. Each put is the
|
|
// key `<node>.<module>` of the assigner's state puts, which holds the version asked, the hold, why, and each step the
|
|
// assigner took or waits on, so a reader watches the key to follow it. The want the put writes carries Put (and Hold),
|
|
// so the assigner's rules pass over that key while the put holds it.
|
|
|
|
// AssignerPutsBucket is the assigner's bucket of puts, `<owner module>_puts`.
|
|
const AssignerPutsBucket = AssignerModule + "_puts"
|
|
|
|
// AssignerPutsHistory is the revisions the puts bucket keeps per key: each step of a put is one.
|
|
const AssignerPutsHistory = 20
|
|
|
|
// A put's steps, in the order they are taken (ADR 0546 clauses 3 to 9). A put stands at the last step written.
|
|
const (
|
|
// PutAsked is a put written by the tool, not taken up by a pass yet.
|
|
PutAsked = "asked"
|
|
// PutBuild waits for the builder's build at the fingerprint.
|
|
PutBuild = "build"
|
|
// PutCompose waits for the controller's composition (and grant) at the fingerprint.
|
|
PutCompose = "compose"
|
|
// PutPerson waits for the operator's answer to the ask about the move.
|
|
PutPerson = "person"
|
|
// PutSnapshot waits for the bus's streams to be snapshotted after the operator's yes.
|
|
PutSnapshot = "snapshot"
|
|
// PutWanted is the want written: the node's have has not reached it yet.
|
|
PutWanted = "wanted"
|
|
// PutHolding is a held put whose have runs it healthy: the want stays until released.
|
|
PutHolding = "holding"
|
|
// PutDone is a put without hold whose have ran it healthy: the rules write the want again.
|
|
PutDone = "done"
|
|
// PutReleased is a put released by the tool `assigner_release`.
|
|
PutReleased = "released"
|
|
// PutRefused is a put that cannot go on: a build that failed, an answer no, a snapshot not taken. Its words say why.
|
|
PutRefused = "refused"
|
|
)
|
|
|
|
// PutEnded says a put at this step is over: nothing more is done for it and the rules own the want.
|
|
func PutEnded(step string) bool {
|
|
return step == PutDone || step == PutReleased || step == PutRefused
|
|
}
|
|
|
|
// PutStep is one step a put took: when, which, and what was done or waits, in a sentence.
|
|
type PutStep struct {
|
|
At time.Time `json:"at"`
|
|
Step string `json:"step"`
|
|
Words string `json:"words"`
|
|
}
|
|
|
|
// PutStepsKept is how many steps a put keeps, newest last.
|
|
const PutStepsKept = 16
|
|
|
|
// Put is the value of a key of AssignerPutsBucket.
|
|
type Put struct {
|
|
V int `json:"v"`
|
|
// FP is the fingerprint put, of the new form.
|
|
FP string `json:"fp"`
|
|
// Hold keeps the want at FP until released.
|
|
Hold bool `json:"hold,omitempty"`
|
|
Why string `json:"why"`
|
|
// By is who asked, as the bus named the caller; "unproven" when it named none.
|
|
By string `json:"by,omitempty"`
|
|
At time.Time `json:"at"`
|
|
// Step is where the put stands now, one of the Put* steps; Words say it in a sentence.
|
|
Step string `json:"step"`
|
|
Words string `json:"words,omitempty"`
|
|
// Composed is the digest of the composition the want names, once known.
|
|
Composed string `json:"composed,omitempty"`
|
|
// Ask is the key, in AssignerAsksBucket, of the ask about the move, once asked.
|
|
Ask string `json:"ask,omitempty"`
|
|
// Snapshot says where the bus's streams were snapshotted, once they were.
|
|
Snapshot string `json:"snapshot,omitempty"`
|
|
// Steps are the steps taken, oldest first, at most PutStepsKept.
|
|
Steps []PutStep `json:"steps,omitempty"`
|
|
}
|
|
|
|
// Said is p at step with words, the step added to its steps when it differs from the last one.
|
|
func (p Put) Said(at time.Time, step, words string) Put {
|
|
if p.Step == step && p.Words == words {
|
|
return p
|
|
}
|
|
p.Step, p.Words = step, words
|
|
p.Steps = append(append([]PutStep(nil), p.Steps...), PutStep{At: at.UTC(), Step: step, Words: words})
|
|
if len(p.Steps) > PutStepsKept {
|
|
p.Steps = p.Steps[len(p.Steps)-PutStepsKept:]
|
|
}
|
|
return p
|
|
}
|
|
|
|
func (p Put) check() error {
|
|
if err := checkFingerprint(p.FP, "a put's fingerprint"); err != nil {
|
|
return err
|
|
}
|
|
if p.Why == "" {
|
|
return fmt.Errorf("delivery: a put says why")
|
|
}
|
|
switch p.Step {
|
|
case PutAsked, PutBuild, PutCompose, PutPerson, PutSnapshot, PutWanted, PutHolding, PutDone, PutReleased, PutRefused:
|
|
default:
|
|
return fmt.Errorf("delivery: %q is not a step of a put", p.Step)
|
|
}
|
|
if p.Composed != "" {
|
|
return checkDigest(p.Composed, "a put's composition digest")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// PutKey is the key, in AssignerPutsBucket, of the put of module on node: `<node>.<module>`.
|
|
func PutKey(node, module string) (string, error) {
|
|
return HaveKey(node, module)
|
|
}
|
|
|
|
// ParsePutKey reads a PutKey.
|
|
func ParsePutKey(key string) (node, module string, err error) {
|
|
node, module, isNode, err := ParseHaveKey(key)
|
|
if err == nil && isNode {
|
|
err = fmt.Errorf("delivery: %q is a node's own key, and no put", key)
|
|
}
|
|
return node, module, err
|
|
}
|
|
|
|
// EncodePut is p as JSON at Version; it refuses a fingerprint not of the new form, a put that says no why and an
|
|
// unknown step.
|
|
func EncodePut(p Put) ([]byte, error) {
|
|
if err := p.check(); err != nil {
|
|
return nil, err
|
|
}
|
|
p.V = Version
|
|
return json.Marshal(p)
|
|
}
|
|
|
|
// DecodePut reads a put; it refuses an unknown version (ErrUnknownVersion) and what EncodePut refuses.
|
|
func DecodePut(data []byte) (Put, error) {
|
|
var p Put
|
|
if err := decode(data, &p); err != nil {
|
|
return Put{}, err
|
|
}
|
|
if err := p.check(); err != nil {
|
|
return Put{}, err
|
|
}
|
|
return p, nil
|
|
}
|