An older build request never replaces a newer one's artifact
Builds of one module in flight together finish in any order, and the mesh took whatever it heard last as what the module is: RegisterModule overwrote the module's manifest unconditionally, and Held/BuiltAgainst/ReadRepositories ordered builds by when they were recorded. A postgres build asked before the mesh-tools runtime fix finished after the one asked after it, and the next push deployed the stale image (novox/hq issue 219). A build is now ordered by when it was asked, read from the build-<nanos> id the controller writes: build.asked and module.built_asked (migration 0055). A registration from an earlier request than the module's current one is recorded and refused as superseded. A plan takes as its outcome only a build asked at or after its own ask, so an earlier plan's leftover build cannot settle a later plan. Ids of any other shape keep the old order.
This commit is contained in:
@@ -288,7 +288,13 @@ func askTier(ctx context.Context, inv *inventory.Inventory, p *inventory.Plan) e
|
||||
|
||||
// planBuilt marks a module built (or failed) in every open plan whose current tier holds it, and
|
||||
// advances what that completes. Called from the daemon's take-in of every outcome.
|
||||
func planBuilt(ctx context.Context, open *stores, module, commit, failed string) {
|
||||
//
|
||||
// **Only a build asked at or after the plan's ask is its outcome** (novox/hq 04-ISSUES/219). Two
|
||||
// plans a few minutes apart both ask for a module; the earlier plan's build, finishing late, is not
|
||||
// the later plan's answer — it stood on the bases from before the later plan's merge, and taking it
|
||||
// would send machines, and the next tier, what the later merge replaced. asked is zero when the
|
||||
// build's request time is not known, and such an outcome is taken as before.
|
||||
func planBuilt(ctx context.Context, open *stores, module, commit, failed string, asked time.Time) {
|
||||
inv := open.inventory
|
||||
plans, err := inv.OpenPlans(ctx)
|
||||
if err != nil {
|
||||
@@ -315,6 +321,9 @@ func planBuilt(ctx context.Context, open *stores, module, commit, failed string)
|
||||
state = &inventory.PlanModule{}
|
||||
p.Modules[module] = state
|
||||
}
|
||||
if askedBefore(asked, state.AskedAt) {
|
||||
continue
|
||||
}
|
||||
if failed != "" {
|
||||
state.State = "failed"
|
||||
state.Why = failed
|
||||
@@ -549,7 +558,8 @@ func planFailedBuild(ctx context.Context, open *stores, result link.BuildResult)
|
||||
}
|
||||
for _, e := range entries {
|
||||
if repositoryMatches(e.Source.Repository, result.Repository) && e.Source.Path == result.Path {
|
||||
planBuilt(ctx, open, e.Manifest.Module, result.Commit, result.Failed)
|
||||
asked, _ := link.BuildAskedAt(result.ID)
|
||||
planBuilt(ctx, open, e.Manifest.Module, result.Commit, result.Failed, asked)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -791,6 +801,11 @@ func settleFromRecords(p *inventory.Plan, tier []string, recorded map[string][]i
|
||||
if b.At.Before(*s.AskedAt) {
|
||||
break
|
||||
}
|
||||
// Recorded after the ask and asked before it: an earlier ask's late outcome, not this
|
||||
// one's (novox/hq 04-ISSUES/219).
|
||||
if askedBefore(b.Asked, s.AskedAt) {
|
||||
continue
|
||||
}
|
||||
outcome = &b
|
||||
}
|
||||
if outcome == nil {
|
||||
@@ -812,3 +827,9 @@ func settleFromRecords(p *inventory.Plan, tier []string, recorded map[string][]i
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
// askedBefore is whether a build asked at asked was asked before a plan asked for its module — and
|
||||
// so is not that plan's outcome (novox/hq 04-ISSUES/219). False when either time is not known.
|
||||
func askedBefore(asked time.Time, planAsked *time.Time) bool {
|
||||
return !asked.IsZero() && planAsked != nil && asked.Before(*planAsked)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user