Make pending assignments safe to race, settle them on a tick, and say only what was checked
Review of #150: a withdrawal could land between the look and the act, a failed ask read as a build in flight, a request kept the wrong asker, a build being registered read as not built, build "true" could ask a build nothing waited on, and a status read changed state. Claim a row under the machine's hold before making it, keep a request only once asked, settle on the controller's own tick, raise an assignment not made as a condition until it is answered, and tie each row to its machine.
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -469,11 +468,8 @@ func theThreeQuestions(ctx context.Context, open *stores) (answers, error) {
|
||||
if out.conditions, err = openConditions(ctx); err != nil {
|
||||
out.conditionsUnread = err.Error()
|
||||
}
|
||||
// And the assignments waiting for their module's build (novox/hq issue 325): what a missed outcome left
|
||||
// waiting is settled first, so one never waits silently past its build.
|
||||
for _, line := range settleStalePending(ctx, open, time.Now()) {
|
||||
fmt.Fprintln(os.Stderr, line)
|
||||
}
|
||||
// And the assignments waiting for their module's build (novox/hq issue 325, ADR 0261), read only: the
|
||||
// controller's tick settles them, never a read.
|
||||
if out.pending, err = inv.Pending(ctx, time.Now().Add(-pendingShownFor)); err != nil {
|
||||
out.pendingUnread = err.Error()
|
||||
err = nil
|
||||
@@ -610,13 +606,14 @@ func (a answers) well() bool {
|
||||
return len(a.wrong) == 0 && len(a.quiet) == 0 && len(a.behind) == 0 &&
|
||||
len(a.waiting) == 0 && len(a.refused) == 0 && a.network == "" && len(a.untaken) == 0 &&
|
||||
len(a.filtered) == 0 && len(a.unheld) == 0 && len(a.overflowing) == 0 &&
|
||||
len(a.conditions) == 0 && a.conditionsUnread == "" && a.pendingUnread == "" && !pendingNotWell(a.pending)
|
||||
len(a.conditions) == 0 && a.conditionsUnread == "" && a.pendingUnread == "" && !pendingOpen(a.pending)
|
||||
}
|
||||
|
||||
// pendingNotWell is whether any pending assignment is waiting, or ended without being made.
|
||||
func pendingNotWell(pending []inventory.PendingAssignment) bool {
|
||||
// pendingOpen is whether any pending assignment is still to be made. One that ended without being made is
|
||||
// not counted here: it is a condition, open until it is answered (ADR 0261).
|
||||
func pendingOpen(pending []inventory.PendingAssignment) bool {
|
||||
for _, p := range pending {
|
||||
if p.State != inventory.PendingApplied && p.State != inventory.PendingWithdrawn {
|
||||
if p.Open() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -632,7 +629,7 @@ func printPending(pending []inventory.PendingAssignment, unread string) {
|
||||
}
|
||||
var waiting, ended []inventory.PendingAssignment
|
||||
for _, p := range pending {
|
||||
if p.State == inventory.PendingWaiting {
|
||||
if p.Open() {
|
||||
waiting = append(waiting, p)
|
||||
} else {
|
||||
ended = append(ended, p)
|
||||
|
||||
Reference in New Issue
Block a user