Refuse every send that would replace the bus outside its planned step (hq ADR 0236)
A plan's send to the bus's machine for another module carried the bus's new build and restarted it under every machine with nobody asking (2026-10-06). The guard is in the one send everything uses; only the bus step passes it. A rebuild that made the same artifacts is no move.
This commit is contained in:
@@ -54,12 +54,19 @@ type busPending struct {
|
||||
machines []string
|
||||
from map[string]string
|
||||
to string
|
||||
// same are the commits whose build made the same artifacts as the build the mesh holds.
|
||||
same map[string]bool
|
||||
}
|
||||
|
||||
// moves is whether sending the machine would replace its bus.
|
||||
// moves is whether sending the machine would replace its bus: a build it was not last sent, unless the
|
||||
// two builds made the same artifacts — a rebuild of the same source for another module's merge changes
|
||||
// nothing the machine runs.
|
||||
func (b busPending) moves(machine string) bool {
|
||||
from, known := b.from[machine]
|
||||
return b.module != "" && b.to != "" && (!known || !sameCommit(from, b.to))
|
||||
if b.module == "" || b.to == "" || (known && sameCommit(from, b.to)) {
|
||||
return false
|
||||
}
|
||||
return !known || !b.same[from]
|
||||
}
|
||||
|
||||
// pendingBus reads what a bus upgrade would do.
|
||||
@@ -85,7 +92,14 @@ func pendingBus(ctx context.Context, inv *inventory.Inventory) (busPending, erro
|
||||
if b.machines, err = inv.Running(ctx, b.module); err != nil {
|
||||
return b, err
|
||||
}
|
||||
b.from = map[string]string{}
|
||||
b.from, b.same = map[string]string{}, map[string]bool{}
|
||||
made, err := madeBy(ctx, inv, b.module)
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
for commit, refs := range made {
|
||||
b.same[commit] = refs != "" && refs == made[b.to]
|
||||
}
|
||||
for _, n := range b.machines {
|
||||
sent, known, err := inv.SentBuilds(ctx, n)
|
||||
if err != nil {
|
||||
@@ -204,7 +218,7 @@ func busCommand(ctx context.Context, args []string) error {
|
||||
fmt.Printf("bus upgrade %d: %s %s → %s on %s; streams snapshotted at %s; %s\n", step.ID, b.module, step.From,
|
||||
short(b.to), strings.Join(moving, ", "), where, map[bool]string{true: "reversible: putting the old build back undoes it",
|
||||
false: "NOT reversible: the snapshot is the only way back"}[*reversible])
|
||||
sent, err := sendRollout(ctx, open, moving)
|
||||
sent, err := sendRollout(withBusStep(ctx), open, moving)
|
||||
if err != nil {
|
||||
_ = inv.EndBusStep(ctx, step.ID, "failed", "the send was refused: "+err.Error())
|
||||
return fmt.Errorf("the bus's machine could not be sent its new build: %w — nothing was replaced", err)
|
||||
@@ -371,3 +385,40 @@ func snapshotTheBusNow(ctx context.Context, module, node string) (string, error)
|
||||
})
|
||||
return where, err
|
||||
}
|
||||
|
||||
// errBusWaits is a send refused because it would replace the bus outside its planned step.
|
||||
var errBusWaits = errors.New("a new bus build waits for its planned step")
|
||||
|
||||
type busStepKey struct{}
|
||||
|
||||
// withBusStep marks a send as the bus's planned step: the one send that may replace the bus.
|
||||
func withBusStep(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, busStepKey{}, true)
|
||||
}
|
||||
|
||||
func busStepSending(ctx context.Context) bool { on, _ := ctx.Value(busStepKey{}).(bool); return on }
|
||||
|
||||
// madeBy is, per commit, the artifacts the newest worked build of a module from it made, as one sorted
|
||||
// string: what tells a rebuild that changes nothing from one that does.
|
||||
func madeBy(ctx context.Context, inv *inventory.Inventory, module string) (map[string]string, error) {
|
||||
builds, err := inv.Builds(ctx, module, 50)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := map[string]string{}
|
||||
for _, b := range builds {
|
||||
if !b.Worked() || b.Commit == "" {
|
||||
continue
|
||||
}
|
||||
if _, seen := out[b.Commit]; seen {
|
||||
continue
|
||||
}
|
||||
var refs []string
|
||||
for _, a := range b.Made {
|
||||
refs = append(refs, a.Name+"="+a.Reference)
|
||||
}
|
||||
sort.Strings(refs)
|
||||
out[b.Commit] = strings.Join(refs, " ")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user