Files
mesh-delivery/modules/mesh-delivery-watchman/internal/watch/mirror.go
T

55 lines
2.2 KiB
Go

package watch
import (
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// A build ask taken by a node is a move (novox/hq ADR 0525 §4, issues 1887 A8b, 1908, 1909): the node writes the ask's step
// key `<node>.<ask id>` running in the build module's steps (delivery.StepsBucket) when it takes the ask, and writes it passed,
// failed or refused when the ask ends. The pulse of the move is the pulse of the bucket named as the seat's stream
// (delivery.AskStream), under the ask's id, and it begins when the node started the step.
//
// **An ask still waiting in the stream is a backlog, not a stall** (issue 1908): the rebuild after the switch puts about 170
// asks on a few nodes' slots, and most wait for hours with every worker healthy. No pulse is made for a waiting ask, so none
// can expire into a false stuck row; the view shows the backlog and the oldest waiting ask's age (delivery view, A8a). What
// is read of the steps at the watchman's start is mirrored the same way, so an ask running when the watchman was down is
// pulsed again (issue 1909).
// Step is a change of a key of the steps bucket of language's build module, read from the watch (at the start the keys that
// stand, then each change). A running step makes the pulse of its ask, from the step's own start; a step that ended, or a
// key deleted, ends it. The node's `paused.<node>` key, a key that is no step key and a value that cannot be read are left.
func (w *Watchman) Step(language, key string, value []byte, op Op) {
bucket, err := delivery.AskStream(language)
if err != nil {
w.say("no pulse for the step %s: %v", key, err)
return
}
node, id, err := delivery.ParseStepKey(key)
if err != nil {
return
}
w.mu.Lock()
defer w.mu.Unlock()
switch op {
case Expired:
return
case Delete:
w.moved(bucket, id)
return
}
step, err := delivery.DecodeStep(value)
if err != nil {
w.say("the step %s cannot be read, and is left: %v", key, err)
return
}
if step.State != delivery.StepRunning {
w.moved(bucket, id)
return
}
since := step.Started
if since.IsZero() {
since = w.now()
}
w.mirrorWithin(w.stepBound, bucket, id, describe("the ask %s to end on %s", id, node), node, since, 0)
}