J1: a failed have carries the pull it waits on (ENG-9, the lead's ruling on pull-waits; local only)
This commit is contained in:
@@ -369,6 +369,31 @@ type Have struct {
|
||||
// slot that holds it, so a provider and a consumer of one value on one node each keep their own. Written in Sealed's
|
||||
// place by a node-engine that knows it; Sealed is read only from a have written before.
|
||||
SealedAt Seals `json:"sealed-at,omitempty"`
|
||||
// PullWait is, on a failed have, the pull from a store its apply failed on and waits on that store's holder to settle
|
||||
// for (design 51 *What a pull meets in the swap*, issue 1966 ENG-9): nil on every other have, and on a failure that
|
||||
// waits on no holder.
|
||||
PullWait *PullWait `json:"pull-wait,omitempty"`
|
||||
}
|
||||
|
||||
// PullWait is the pull a failed apply met from a store: the image, the seat it came through and that seat's holder, whose
|
||||
// settled the apply is tried again on, when the pull began, and when the apply was last tried again with what triggered
|
||||
// it, in words (empty while it has not been).
|
||||
type PullWait struct {
|
||||
Image string `json:"image"`
|
||||
Seat string `json:"seat,omitempty"`
|
||||
Holder string `json:"holder"`
|
||||
Began time.Time `json:"began"`
|
||||
Retried string `json:"retried,omitempty"`
|
||||
RetriedAt time.Time `json:"retried-at,omitzero"`
|
||||
}
|
||||
|
||||
// samePullWait says whether two pull waits are the same, their times compared as instants.
|
||||
func samePullWait(a, b *PullWait) bool {
|
||||
if a == nil || b == nil {
|
||||
return a == b
|
||||
}
|
||||
return a.Image == b.Image && a.Seat == b.Seat && a.Holder == b.Holder && a.Began.Equal(b.Began) &&
|
||||
a.Retried == b.Retried && a.RetriedAt.Equal(b.RetriedAt)
|
||||
}
|
||||
|
||||
// UserListWritten is the bus's user list as the node-engine of the bus node wrote it to the bus module's file, applied
|
||||
@@ -488,6 +513,9 @@ func (h Have) check() error {
|
||||
if h.Judgement != "" || h.Waits != "" || h.BuildAlone {
|
||||
return fmt.Errorf("delivery: only a have waiting for a yes names a judgement, the composition waiting and whether it changes the build alone")
|
||||
}
|
||||
if h.PullWait != nil && h.Phase != PhaseFailed {
|
||||
return fmt.Errorf("delivery: only a failed have names the pull it waits on, not one %s", h.Phase)
|
||||
}
|
||||
case PhaseWaitingYes:
|
||||
if h.Judgement != JudgedRecreates && h.Judgement != JudgedMovesData && h.Judgement != JudgedCannot {
|
||||
return fmt.Errorf("delivery: a have waiting for a yes names the judgement %q, not recreates, moves-data or cannot-judge", h.Judgement)
|
||||
@@ -498,6 +526,9 @@ func (h Have) check() error {
|
||||
default:
|
||||
return fmt.Errorf("delivery: phase %q is not backing-up, applying, checking, running, failed, removed, held or waiting-yes", h.Phase)
|
||||
}
|
||||
if w := h.PullWait; w != nil && (w.Image == "" || w.Holder == "") {
|
||||
return fmt.Errorf("delivery: a have's pull wait names no image or no holder")
|
||||
}
|
||||
if h.Composed != "" {
|
||||
if err := checkDigest(h.Composed, "the have's composition digest"); err != nil {
|
||||
return err
|
||||
@@ -601,6 +632,10 @@ func DecodePulse(data []byte) (Pulse, error) {
|
||||
func SameHave(a, b Have) bool {
|
||||
ua, ub := a.UserList, b.UserList
|
||||
a.UserList, b.UserList = nil, nil
|
||||
if !samePullWait(a.PullWait, b.PullWait) {
|
||||
return false
|
||||
}
|
||||
a.PullWait, b.PullWait = nil, nil
|
||||
if !slices.Equal(a.Sealed, b.Sealed) || !maps.Equal(a.SealedAt, b.SealedAt) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -452,6 +452,35 @@ func TestSame(t *testing.T) {
|
||||
} else if back, err := DecodeHave(raw); err != nil || !SameHave(back, sa) {
|
||||
t.Errorf("sealed values do not travel: %+v, %v", back, err)
|
||||
}
|
||||
// A failed have carries the pull it waits on, compared by what it says (issue 1966 ENG-9); only a failed one does.
|
||||
began := time.Date(2026, 11, 4, 14, 0, 0, 0, time.UTC)
|
||||
pa, pb := a, a
|
||||
pa.Phase, pb.Phase = PhaseFailed, PhaseFailed
|
||||
pa.PullWait = &PullWait{Image: "reg/x@sha256:1", Seat: "container-image-registry", Holder: "distribution", Began: began,
|
||||
Retried: "distribution settled", RetriedAt: began.Add(time.Minute)}
|
||||
w := *pa.PullWait
|
||||
w.Began, w.RetriedAt = began.In(time.Local), w.RetriedAt.In(time.Local)
|
||||
pb.PullWait = &w
|
||||
if !SameHave(pa, pb) || SameHave(pa, Have{V: 1, Build: "b", Phase: PhaseFailed, Health: HealthOK}) {
|
||||
t.Error("equal pull waits differ, or one said and one not are the same")
|
||||
}
|
||||
if raw, err := EncodeHave(pa); err != nil {
|
||||
t.Error(err)
|
||||
} else if back, err := DecodeHave(raw); err != nil || !SameHave(back, pa) {
|
||||
t.Errorf("a pull wait does not travel: %+v, %v", back, err)
|
||||
}
|
||||
pb.PullWait = &PullWait{Image: "reg/x@sha256:1", Holder: "distribution", Began: began}
|
||||
if SameHave(pa, pb) {
|
||||
t.Error("pull waits retried and not are the same")
|
||||
}
|
||||
for name, h := range map[string]Have{
|
||||
"on a running have": {Phase: PhaseRunning, Health: HealthOK, PullWait: pa.PullWait},
|
||||
"naming no holder": {Phase: PhaseFailed, Health: HealthOK, PullWait: &PullWait{Image: "reg/x@sha256:1"}},
|
||||
} {
|
||||
if _, err := EncodeHave(h); err == nil {
|
||||
t.Errorf("a pull wait %s was encoded", name)
|
||||
}
|
||||
}
|
||||
// The user list is compared by what it says, never by where it is held (ADR 0547 §8).
|
||||
at := time.Date(2026, 10, 25, 21, 0, 0, 0, time.UTC)
|
||||
ua, ub := a, a
|
||||
|
||||
Reference in New Issue
Block a user