Files
mesh-host/cmd/mesh-host/settled.go
T

72 lines
2.3 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"github.com/novox/mesh-host/internal/link"
)
// settledEvent is where the status view says a module has settled on a node: its have reached its want, running and healthy
// (design 47; the view's `settled`, said once for a module on a node at one composition). The engine hears it for every module
// and tells its agent, which tries again, once per settled, a failed apply that waits on that module as the holder of the store
// its image comes from (design 51 *distribution's first delivery*, issue 1966 ENG-11). The grants part grants the engine this
// subject (NodeAgentHears); a refused subscription is said, and made again when the next link opens.
const settledEvent = "mesh.mod.mesh-delivery-view.event.settled"
// settledBody is what of the event the engine reads: the module that settled, on whichever node.
type settledBody struct {
Module string `json:"module"`
}
// settledTold is who is told a holder has settled.
type settledTold interface{ Settled(holder string) }
// followSettled hears the status view's `settled` on every link, never on a timer, until ctx ends. now names the agent running
// now (nil while the node agent begins again): a settled heard while there is none is not lost for it, since a new agent applies
// again every have that failed at its start.
func followSettled(ctx context.Context, session *link.Session, now func() settledTold, say link.Announce) {
said := ""
for ctx.Err() == nil {
linked, cancel, err := session.WhenLinked(ctx)
if err != nil {
return
}
events, stop, herr := session.Hear(settledEvent)
if herr != nil {
if line := fmt.Sprintf("a store settling is not heard yet (%s: %v): a failed pull waits for the next link, or for compose", settledEvent, herr); line != said {
said = line
say(line)
}
} else {
said = ""
listen(linked, events, now, say)
stop()
}
<-linked.Done()
cancel()
}
}
// listen tells the agent each settled it hears, until the link ends.
func listen(linked context.Context, events <-chan []byte, now func() settledTold, say link.Announce) {
for {
select {
case <-linked.Done():
return
case raw, ok := <-events:
if !ok {
return
}
var b settledBody
if json.Unmarshal(raw, &b) != nil || b.Module == "" {
continue
}
if told := now(); told != nil {
told.Settled(b.Module)
}
}
}
}