Files
mesh-catalog/modules/mesh-build-node/cmd/mesh-build-node/asks.go
T
jschoubben 3f8b0b4248
mesh/delivery-group group fix/capacity-follows-cpu-share rejected: composed together: the checker's verdict at the members' heads (63694fe9222d): unit: ..test
mesh/delivery closed: a newer head of the same pull request
mesh/check checking 3f8b0b42480b on 7c5c29421f02 | novox/mesh-catalog#511 in group fix/capacity-follows-cpu-share
Build modules take asks only within their node's build hours
mesh-build-go, -node and -image declare build-hours (node=HH:MM-HH:MM in the node's local time,
empty = any hour) and hand it to the SDK puller (the operator, 2026-10-26: g14 builds only from
18:00 to 06:00); their SDK pin moves to mesh-sdk d00dac1, which has it.
2026-10-26 21:22:09 +01:00

93 lines
3.9 KiB
Go

package main
import (
"context"
stdio "git.novox.be/novox/mesh-sdk/go"
"git.novox.be/novox/mesh-sdk/go/buildstep"
"git.novox.be/novox/mesh-sdk/go/delivery"
)
// **The module pulls its seat's asks** (novox/hq ADR 0525 §2-§6, ADR 0536 §4; issue 1887 A3node), as mesh-build-go
// does: the seat node-build-node, delivery first, then check, then recheck, at most the node's build capacity at once
// (its setting `capacity`); each ask runs with the step bodies its tools run, behind the same guard, and ends on the key
// <node>.<ask id>. The tools stay as the hand path (ADR 0525 §8).
// Seat is the node seat this module holds.
const Seat = "node-build-node"
func (m *Module) askSteps(steps []StepTool) buildstep.AskSteps {
byName := map[string]buildstep.StepFunc{}
for _, s := range steps {
run := s.Run
byName[s.Name] = func(ctx context.Context, args map[string]any) (any, error) {
defer m.holdArg(args)()
return run(ctx, args)
}
}
return buildstep.AskSteps{
Fetch: byName["build_node_fetch"], Build: byName["build_node_build"], Test: byName["build_node_test"],
Toolchain: func(ctx context.Context) (delivery.ToolchainUsed, error) {
installed, err := m.Probe(ctx)
if err != nil {
return delivery.ToolchainUsed{}, err
}
return delivery.ToolchainUsed{Version: installed, Recipe: m.recipe().Version()}, nil
},
Release: func(ws string) error { return m.spaces().Release(ws) },
Logf: m.Say,
}
}
// Puller is the module's pull of its seat's asks, on source (the runtime's seat pull when nil).
func (m *Module) Puller(steps []StepTool, source buildstep.AskSource) *buildstep.Puller {
if source == nil {
source = buildstep.SeatAsks{Language: delivery.AskNode}
}
capacity := m.Capacity
// The capacity's own change wakes the puller (issue 1887): the runtime's watch of the config value as mesh-config
// resolved it; the settings file is read only when that watch cannot start. A test's Capacity is its own.
var watch func(string, func(stdio.ProvisionChange) error) error
// And the CPU bounds it (issue 1806's follow-up): the configured capacity is an upper bound, the node's build slice
// gives floor(its quota's cores / the module's cores-per-step) at once, read live; a test judges by its own Capacity.
// And the node's build hours (the operator, 2026-10-26: g14 builds only from 18:00 to 06:00): outside them it takes
// nothing new.
var cores func() float64
var hours func() (*buildstep.BuildWindow, string)
if capacity == nil {
hours = buildstep.NodeBuildHours(m.Settings, m.Node, m.Say)
capacity = buildstep.NodeCapacity(m.Settings, buildstep.DefaultCapacities, m.Node, m.Say)
watch = buildstep.WatchConfigServed
cores = buildstep.NodeCoresPerStep(m.Settings, buildstep.DefaultCoresPerStep[delivery.AskNode], m.Say)
}
ask := m.askSteps(steps)
var load func(string) ([]byte, error)
if m.ReadPauses.Get != nil {
load = func(key string) ([]byte, error) { return m.ReadPauses.Get(key) }
}
return &buildstep.Puller{Source: source, Language: delivery.AskNode, Node: m.Node, Put: m.Steps, PausePut: m.Pauses, Load: load,
Capacity: capacity, WatchConfig: watch, CoresPerStep: cores, BuildHours: hours, Logf: m.Say,
Run: func(ctx context.Context, a delivery.StepAsk) (any, error) {
if err := m.Prepare(ctx); err != nil {
return nil, err
}
if err := m.room(); err != nil {
return nil, err
}
return buildstep.RunAsk(ctx, ask, a)
}}
}
// SeatTools are the seat's verbs on this node (ADR 0525 §10).
func (m *Module) SeatTools(p *buildstep.Puller) []stdio.Tool {
return buildstep.SeatTools(Seat, "Node", p)
}
// StepEndTool ends one step left running (issue 1890); the module's steps state is the one it reads and writes.
const StepEndTool = "build_node_step_end"
// stepScan is the module's steps state as buildstep reads it.
func (m *Module) stepScan() buildstep.Scan {
return buildstep.ScanOf(stdio.State(delivery.StepsState))
}