fix(cluster): stop saying "waiting for spots" when 76 have arrived
An operator sent two screenshots: 76 LIVE in the counter, and the panel beside it reading "Waiting for spots… Spots will appear as the cluster sends them." Both his band and mode were locked to the rig — 20 m, SSB — so the filters were doing exactly their job and the empty state was describing a different problem entirely. He went looking for a connection fault. It now says how many arrived, names every filter currently narrowing the list, and offers one button to clear them all. The band and mode locks are named first: they follow the rig rather than a click, so they are the two nobody remembers switching on. Also times the connection. He reports the first launch taking a while to produce spots and a restart connecting instantly, which is the signature of a slow name resolution rather than a slow node — the OS caches the answer, so the second run skips it. The log now carries the dial duration and the delay to the first spot, which separates that from a node that simply had nothing to say. Hypothesis, not conclusion: the next log settles it.
This commit is contained in:
@@ -369,10 +369,21 @@ func (s *session) runOnce() (time.Time, error) {
|
||||
// failure surfaces as an error on Read — which is the only thing that ends
|
||||
// a session below.
|
||||
d := net.Dialer{Timeout: 10 * time.Second, KeepAlive: 30 * time.Second}
|
||||
// TIMED, and reported. An operator sees "connected" and no spots for a
|
||||
// minute on the first launch, then an instant connection when the program is
|
||||
// restarted — which is the signature of a slow name resolution rather than a
|
||||
// slow cluster (the OS caches the answer, so the second run skips it). The
|
||||
// only way to tell that from a node that simply had nothing to say is to
|
||||
// know how long the dial itself took.
|
||||
dialStart := time.Now()
|
||||
conn, err := d.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
applog.Printf("cluster[%s] dial %s failed after %s: %v", s.cfg.Name, addr, time.Since(dialStart).Round(time.Millisecond), err)
|
||||
return time.Time{}, fmt.Errorf("dial %s: %w", addr, err)
|
||||
}
|
||||
applog.Printf("cluster[%s] connected to %s in %s", s.cfg.Name, addr, time.Since(dialStart).Round(time.Millisecond))
|
||||
linkUpAt := time.Now()
|
||||
firstSpotLogged := false
|
||||
s.mu.Lock()
|
||||
s.conn = conn
|
||||
s.mu.Unlock()
|
||||
@@ -556,6 +567,13 @@ func (s *session) runOnce() (time.Time, error) {
|
||||
}
|
||||
s.mu.Unlock()
|
||||
if s.onSpot != nil {
|
||||
if !firstSpotLogged {
|
||||
firstSpotLogged = true
|
||||
// The gap between the socket opening and the first spot is the
|
||||
// other half of the answer: a long dial is the network, a quick
|
||||
// dial and a long silence is the node (or the login) instead.
|
||||
applog.Printf("cluster[%s] first spot %s after connecting", s.cfg.Name, time.Since(linkUpAt).Round(time.Millisecond))
|
||||
}
|
||||
s.onSpot(spot)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user