diff --git a/modules/mesh-grants/grants_test.go b/modules/mesh-grants/grants_test.go index 1260d16..449da6e 100644 --- a/modules/mesh-grants/grants_test.go +++ b/modules/mesh-grants/grants_test.go @@ -2309,6 +2309,12 @@ func TestGrants(t *testing.T) { len(behind) == 0 || behind[len(behind)-1].State != asks.StateRaised || !strings.Contains(behind[len(behind)-1].Explanation, "EVENTS.b_mod-c") { t.Fatalf("a consumer far behind: %+v, said %+v", res.Consumers, behind) } + // Still behind at the next pass, by another count: the condition names the consumers alone, so it is not said again. + made["pending"] = grants.BehindBound + 50 + n := len(behind) + if res = p.Compose(); len(res.Consumers.Behind) != 1 || len(behind) != n { + t.Fatalf("a consumer still behind by another count was said again: %+v", behind[n-1:]) + } made["pending"] = grants.BehindBound res = p.Compose() if len(res.Consumers.Behind) != 0 || behind[len(behind)-1].State != asks.StateCleared { diff --git a/modules/mesh-grants/internal/grants/consumers.go b/modules/mesh-grants/internal/grants/consumers.go index d5a0c9a..19e1bcf 100644 --- a/modules/mesh-grants/internal/grants/consumers.go +++ b/modules/mesh-grants/internal/grants/consumers.go @@ -256,7 +256,15 @@ func (p *Part) sayBehind(st *ConsumersState) { if p.Say == nil { return } - why := strings.Join(st.Behind, "; ") + // The consumers alone decide whether it is said again, never how far each is behind, which changes every pass: the + // counts stay in the last pass's consumers.behind (its state user-list, key pass), and the condition is not said again + // for them. + var names []string + for _, b := range st.Behind { + name, _, _ := strings.Cut(b, ": ") + names = append(names, name) + } + why := strings.Join(names, ", ") p.holdMu.Lock() defer p.holdMu.Unlock() if p.behindKnown && why == p.behindSaid { @@ -270,7 +278,7 @@ func (p *Part) sayBehind(st *ConsumersState) { c.Summary = fmt.Sprintf("%d durable consumers are more than %d messages behind their stream's head", len(st.Behind), BehindBound) c.Headline, c.Needs = "Messages pile up for a listener", "a look at the module that reads them" c.Explanation = asks.NeedsYou + "a look. These consumers stayed far behind their stream's head at two passes " + - "running, so what is sent to their modules waits unread: " + why + "running, so what is sent to their modules waits unread (how far each is, in the grants part's last pass): " + why c.Resolved = "every account consumer is back within the bound" } if p.Say(c) == nil {