Ask the operator for a condition's answers and act on the warrant, so release, stop, start and restart can be answered from any channel that proves who answered (hq ADR 0259)
This commit is contained in:
@@ -47,6 +47,10 @@ var Contracts = map[string]Contract{
|
||||
KindPullUpdated: {Unordered: "a pull request's head, asked to be checked: each head is its own commit, and its " +
|
||||
"verdict is set on that commit alone, so a head heard late is checked and judged as itself and never " +
|
||||
"stands for a newer one (novox/hq to-be 45 §9)"},
|
||||
KindDecided: {Unordered: "the router's word on one ask, by the ask's id: an ask is ended once, by compare-and-set " +
|
||||
"at the router, and the controller acts on it once, recording that it did under the ask's id — so a word " +
|
||||
"heard again, or late, does nothing more (novox/hq ADR 0259)",
|
||||
Tests: []string{"TestAWarrantIsActedOnOnce"}},
|
||||
KindCatchUp: {Unordered: "a catalogue asking what it missed: answered from the record, whenever asked"},
|
||||
KindProvisioner: {Unordered: "a provider's newest word about a consumer, said again every fifteen minutes " +
|
||||
"while it holds (ADR 0224): the condition keeps the last observed, and S8 says when the words stop. " +
|
||||
|
||||
@@ -49,6 +49,16 @@ type HandAct struct {
|
||||
Kind string `json:"kind,omitempty"`
|
||||
// Carried is what such a push moved, one "module from → to" per module, so the log says it.
|
||||
Carried []string `json:"carried,omitempty"`
|
||||
// Via, Ask, Proofs and RequestedBy are an act the operator chose on a warrant (novox/hq ADR 0234 §8, ADR
|
||||
// 0259): the channel it came through (module and kind, and how the sender was known), the ask's id, the
|
||||
// proofs present (P1, P2, P3), and what asked (a condition's key). By then names the operator as that
|
||||
// kind's identity. Absent from every other act.
|
||||
Via string `json:"via,omitempty"`
|
||||
Ask string `json:"ask,omitempty"`
|
||||
Proofs []string `json:"proofs,omitempty"`
|
||||
RequestedBy string `json:"requested-by,omitempty"`
|
||||
// Outcome is what came of an act recorded after it was done: done, or the verb's refusal.
|
||||
Outcome string `json:"outcome,omitempty"`
|
||||
}
|
||||
|
||||
// KindRecordedBuilds is a push that only moved recorded builds: the person's word their `record` policy
|
||||
|
||||
@@ -44,6 +44,9 @@ const (
|
||||
// KindPullUpdated is the forge announcing a pull request's new head: checked before it merges
|
||||
// (novox/hq to-be 45 §9).
|
||||
KindPullUpdated = "pull-updated"
|
||||
// KindDecided is the router's warrant for an ask the controller made, or that ask's end without one
|
||||
// (novox/hq ADR 0259): said to the controller alone, under its own name.
|
||||
KindDecided = "decided"
|
||||
)
|
||||
|
||||
// Control is one thing a node or a module said, as the controller must act on it.
|
||||
|
||||
@@ -53,7 +53,7 @@ func Nats(js *broker.JetStream) Inbound {
|
||||
// whatever was asked for — and not at all when nothing was.
|
||||
func (n *natsInbound) Also(kind string) error {
|
||||
switch kind {
|
||||
case KindModuleMoved, KindCatchUp, KindSourceMoved, KindProvisioner, KindPullUpdated:
|
||||
case KindModuleMoved, KindCatchUp, KindSourceMoved, KindProvisioner, KindPullUpdated, KindDecided:
|
||||
n.follows[kind] = true
|
||||
return nil
|
||||
default:
|
||||
@@ -259,6 +259,8 @@ func kindOfSubject(subject string) (string, bool) {
|
||||
return KindSourceMoved, true
|
||||
case PullUpdatedSubject:
|
||||
return KindPullUpdated, true
|
||||
case broker.DecidedSubject:
|
||||
return KindDecided, true
|
||||
case BuildOutcome(), BuildOutcomeOf(TheBuildMachineBefore):
|
||||
// A build's outcome is the role's event now, so it arrives on the events stream rather than
|
||||
// the control branch — and is acted on by the same handler, because what the controller does
|
||||
|
||||
+38
-1
@@ -70,7 +70,7 @@ type Checker interface {
|
||||
}
|
||||
|
||||
// PullUpdatedSubject is where the forge's pull requests land: the controller's own follow of them.
|
||||
var PullUpdatedSubject = broker.ControllerFollows[len(broker.ControllerFollows)-1]
|
||||
var PullUpdatedSubject = "mesh.mod.gitea.event.pull.updated"
|
||||
|
||||
// Server acts on what nodes and modules say.
|
||||
//
|
||||
@@ -96,6 +96,8 @@ type Server struct {
|
||||
checker Checker
|
||||
// healths keeps what machines say of their long-running resources (novox/hq ADR 0240).
|
||||
healths Healths
|
||||
// decider acts on the operator's warrants for what the controller asked (novox/hq ADR 0259).
|
||||
decider Decider
|
||||
|
||||
log *log.Logger
|
||||
// giveUp is how long one message is held for the store; zero means GiveUpAfter.
|
||||
@@ -138,6 +140,21 @@ func (s *Server) Checks(c Checker) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decider is what the controller does with the router's word on an ask it made (novox/hq ADR 0259): act
|
||||
// on a warrant once, or record how the ask ended without one.
|
||||
type Decider interface {
|
||||
Decided(ctx context.Context, body []byte) error
|
||||
}
|
||||
|
||||
// Decides says what to do about the router's word on the controller's asks, and asks for it delivered.
|
||||
func (s *Server) Decides(d Decider) error {
|
||||
if err := s.inbound.Also(KindDecided); err != nil {
|
||||
return err
|
||||
}
|
||||
s.decider = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Answers says what to do about a catalogue's catch-up request, and asks for them to be delivered.
|
||||
func (s *Server) Answers(r Replayer) error {
|
||||
if err := s.inbound.Also(KindCatchUp); err != nil {
|
||||
@@ -210,6 +227,8 @@ func (s *Server) act(ctx context.Context, m Control) {
|
||||
s.provisioner(ctx, m)
|
||||
case KindPullUpdated:
|
||||
s.pullUpdated(ctx, m)
|
||||
case KindDecided:
|
||||
s.decided(ctx, m)
|
||||
default:
|
||||
// Dropped: a message nothing understands will not be understood on the next attempt
|
||||
// either, and asking for it again would spin.
|
||||
@@ -656,6 +675,24 @@ func (s *Server) pullUpdated(ctx context.Context, m Control) {
|
||||
_ = m.Took()
|
||||
}
|
||||
|
||||
// decided hands the router's word on an ask to the decider; a failure to keep what it did is held for the
|
||||
// store, like any word that must not be lost.
|
||||
func (s *Server) decided(ctx context.Context, m Control) {
|
||||
if s.decider == nil {
|
||||
_ = m.Took()
|
||||
return
|
||||
}
|
||||
err := s.decider.Decided(ctx, m.Body())
|
||||
switch s.decide(ctx, m, "the operator's word on an ask", "", "", err) {
|
||||
case Hold:
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
s.log.Printf("the operator's word on an ask could not be kept: %v", err)
|
||||
}
|
||||
_ = m.Took()
|
||||
}
|
||||
|
||||
// saysWhatItDid states what a machine now runs, or what it would not take, as a fact on the bus
|
||||
// (novox/hq ADR 0134).
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user