node-tools: only a call pattern names a caller, and a fall-back for want of a responder is said (hq issue 365, review)
mesh/merge-gate pass: builds mesh-tools, node-tools → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of …
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery delivered
mesh/merge-gate pass: builds mesh-tools, node-tools → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of …
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery delivered
callerOn reads a caller only under the call kind, so a tool subscription ending in a wildcard never yields one. A caller-named call that reached nobody is said once per subject before it is asked on the old subject, so a runtime or grant that drifted behind is seen rather than a quiet unproven. The caller tests wait for their bundle's exit, which reads the launcher's restart pauses another test sets.
This commit is contained in:
@@ -91,7 +91,11 @@ func calledPattern(subject string) string {
|
||||
// callerOn is the bus user a call names, from the subject it arrived on: its last token, under a pattern
|
||||
// calledPattern made. "" — said by the module as Unproven — for a call on the subject that names no caller.
|
||||
func callerOn(pattern, subject string) string {
|
||||
if !strings.HasSuffix(pattern, ".*") {
|
||||
// Only the `call` kind names a caller: a `tool` pattern ending in a wildcard (a node seat's verb on any
|
||||
// machine) is never read as one.
|
||||
parts := strings.SplitN(pattern, ".", 5)
|
||||
if len(parts) != 5 || parts[0] != "mesh" || (parts[1] != "mod" && parts[1] != "seat") || parts[3] != CallKind ||
|
||||
!strings.HasSuffix(pattern, ".*") {
|
||||
return ""
|
||||
}
|
||||
dot := strings.LastIndex(subject, ".")
|
||||
@@ -107,9 +111,11 @@ type CalledHandler func(caller string, body json.RawMessage) (any, error)
|
||||
// callers is what a connection keeps of its caller-named calls: those in flight, by subject, so a refused
|
||||
// publish ends its call at once instead of after RequestTimeout.
|
||||
type callers struct {
|
||||
mu sync.Mutex
|
||||
next uint64
|
||||
pending map[string]map[uint64]context.CancelCauseFunc
|
||||
mu sync.Mutex
|
||||
// fellBack are the caller-named subjects already said to have reached nobody, so each is said once.
|
||||
fellBack map[string]bool
|
||||
next uint64
|
||||
pending map[string]map[uint64]context.CancelCauseFunc
|
||||
}
|
||||
|
||||
// errCallRefused is the bus refusing a caller-named publish: this user is not granted it yet (the controller's
|
||||
@@ -176,6 +182,7 @@ func (c *Conn) askCalled(subject string, data []byte) (answered Answered, handin
|
||||
case errors.Is(context.Cause(ctx), errCallRefused):
|
||||
return Answered{}, false, true, nil
|
||||
case errors.Is(err, nats.ErrNoResponders):
|
||||
c.saidFallBack(subject)
|
||||
return Answered{}, false, true, nil
|
||||
case errors.Is(err, context.DeadlineExceeded) || errors.Is(err, nats.ErrTimeout):
|
||||
return Answered{}, false, false, errors.New("timeout")
|
||||
@@ -185,3 +192,21 @@ func (c *Conn) askCalled(subject string, data []byte) (answered Answered, handin
|
||||
answered, handingOver, err = c.answerOf(subject, msg.Data)
|
||||
return answered, handingOver, false, err
|
||||
}
|
||||
|
||||
// saidFallBack says, once per subject, that a caller-named call reached nobody and is asked on the subject that
|
||||
// names no caller: a runtime or holder not yet serving it, or a grant that drifted, is seen in the log rather
|
||||
// than read later as a quiet "unproven" (novox/hq issue 365; expected for the controller's seat until hq issue
|
||||
// 464).
|
||||
func (c *Conn) saidFallBack(subject string) {
|
||||
c.calls.mu.Lock()
|
||||
if c.calls.fellBack == nil {
|
||||
c.calls.fellBack = map[string]bool{}
|
||||
}
|
||||
first := !c.calls.fellBack[subject]
|
||||
c.calls.fellBack[subject] = true
|
||||
c.calls.mu.Unlock()
|
||||
if first {
|
||||
c.Logf("[mesh-tools] nothing answers the caller-named %s; asked on the subject that names no caller, where "+
|
||||
"the module is told no caller (said once per subject; novox/hq issue 365)", subject)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user