d555f54529
A Lane's pace, its refusal backoff and whether its Site needs the browser were only ever visible in the log. The admin page (issue #102) has to state them, so the Poller keeps one snapshot per Lane. - LaneState/Status (status.go) is the page's view of a Lane: due, gap, clamped, refusing, browser. - runOnce records a snapshot on every return path, including the pass that refuses, so a cooling Lane does not read as one that never ran. - Refusing is derived at snapshot read time from the backoff, not stored: a Lane that cooled down between passes must report false without a new pass. - LaneStatus reports only Sites that have completed a pass, so a fresh restart renders "no data yet" instead of confident zeroes.
64 lines
2.0 KiB
Go
64 lines
2.0 KiB
Go
package latest
|
|
|
|
import "time"
|
|
|
|
// LaneState is the administrative page's view of one Poll Lane (issue #102):
|
|
// what the Lane's last completed pass saw. Due and Gap are filled in as the
|
|
// pass computes them, so a pass that returned before reaching a figure (Lane
|
|
// in refusal backoff, no fetcher) records a zero in its place.
|
|
type LaneState struct {
|
|
Site string
|
|
Due int
|
|
LastRun time.Time
|
|
Gap time.Duration
|
|
Clamped bool
|
|
Refusing bool
|
|
Browser bool
|
|
}
|
|
|
|
// Status is the owner's page snapshot of the whole poller (issue #102).
|
|
type Status struct {
|
|
Lanes []LaneState
|
|
BrowserConfigured bool
|
|
BrowserReachable bool
|
|
}
|
|
|
|
// LaneStatus returns a copy of the poller's Lane state for the owner's page.
|
|
// Only Sites that have completed a pass appear — a restart therefore renders
|
|
// "no data yet" instead of confident zeroes — in the same order Run iterates.
|
|
// Refusing is derived at snapshot time from the refusal backoff, not stored,
|
|
// so a Lane that cooled down between passes reports false without a new pass.
|
|
// BrowserReachable mirrors the Lanes' own gate: the sidecar is down only
|
|
// within the refuseBackoff window since its last loss.
|
|
func (p *Poller) LaneStatus() Status {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
lanes := make([]LaneState, 0, len(p.laneStates))
|
|
now := p.Now()
|
|
for _, name := range laneNames() {
|
|
st, ok := p.laneStates[name]
|
|
if !ok {
|
|
continue
|
|
}
|
|
st.Refusing = now.Before(p.refuseUntil[name])
|
|
lanes = append(lanes, st)
|
|
}
|
|
configured := p.BrowserFetch != nil
|
|
reachable := configured
|
|
if reachable && !p.browserDownAt.IsZero() && now.Sub(p.browserDownAt) < refuseBackoff {
|
|
reachable = false
|
|
}
|
|
return Status{Lanes: lanes, BrowserConfigured: configured, BrowserReachable: reachable}
|
|
}
|
|
|
|
// recordLaneState stores one Lane's last pass for LaneStatus. Called deferred
|
|
// from runLanePass so every return path records, even a pass that refused.
|
|
func (p *Poller) recordLaneState(st LaneState) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.laneStates == nil {
|
|
p.laneStates = make(map[string]LaneState)
|
|
}
|
|
p.laneStates[st.Site] = st
|
|
}
|