diff --git a/cmd/mesh-controller/release_plan.go b/cmd/mesh-controller/release_plan.go index cb508b9..535433e 100644 --- a/cmd/mesh-controller/release_plan.go +++ b/cmd/mesh-controller/release_plan.go @@ -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