A plan rolls out every tier it built

A dependent rebuilt because its base moved, or a module that packages another repository's source,
keeps its source commit; the catalogue announces no move for it, and its machines kept the old image
until somebody pushed — forty-three modules after every runtime-image merge (hq issue 189). When a tier
is built, the plan now sends the machines of every module in it whose policy rolls out, once, moved
commit or not; a module whose policy records is built and left, as its policy says. The gate between
tiers waits as before for the ones a later tier is built by.
This commit is contained in:
2026-10-01 22:21:42 +02:00
parent 6ff449e363
commit 477d3ac9a7
+26 -12
View File
@@ -395,7 +395,32 @@ func advanceOnce(ctx context.Context, open *stores, p *inventory.Plan,
latest = *s.BuiltAt
}
}
// Built: wait for what the next tier needs running.
// Built: send every module of the tier whose policy rolls out, once, to the machines running
// it — whether or not its source commit moved. A dependent rebuilt because its base moved, or
// a module that packages another repository's source, keeps its commit; the catalogue announces
// no move for it and its machines would keep the old image until somebody pushed (novox/hq
// issue 189). A module whose policy records is built and left, as its policy says.
for _, m := range tier {
state := p.Modules[m]
if state == nil || state.SentAt != nil || !rollsOut(m) {
continue
}
running, err := inv.Running(ctx, m)
if err != nil {
return false, err
}
now := time.Now().UTC()
state.SentAt = &now
if len(running) == 0 {
continue
}
if err := sendTo(ctx, open, running); err != nil {
return false, fmt.Errorf("sending %s to %s after tier %d: %w", m, strings.Join(running, ", "), p.Tier, err)
}
fmt.Printf("%s: tier %d built; sent %s to %s\n", p.ID, p.Tier, m, strings.Join(running, ", "))
return true, nil
}
// And wait for what the next tier needs running.
needed := gates(*p, edges, rollsOut)
if len(needed) > 0 {
reports, err := inv.LastReports(ctx)
@@ -417,17 +442,6 @@ func advanceOnce(ctx context.Context, open *stores, p *inventory.Plan,
// move the catalogue announces — the build machine rebuilt for a controller change
// is one — so the roll-out that opens this gate is the plan's to make, once, and
// the reports that open it are the ones after the send.
if state.SentAt == nil && len(running) > 0 {
if err := sendTo(ctx, open, running); err != nil {
return false, fmt.Errorf("sending %s to %s so tier %d can be built by it: %w",
m, strings.Join(running, ", "), p.Tier+1, err)
}
now := time.Now().UTC()
state.SentAt = &now
fmt.Printf("%s: tier %d built; sent %s to %s, and tier %d waits until it is applied\n",
p.ID, p.Tier, m, strings.Join(running, ", "), p.Tier+1)
return true, nil
}
since := latest
if state.BuiltAt != nil {
since = *state.BuiltAt