f568fb5e8c
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com> Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
80 lines
3.0 KiB
Go
80 lines
3.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 pass saw. Due, Gap and Checked are filled in as the
|
|
// pass computes them; a pass that returned before reaching a figure (refusal
|
|
// backoff, sidecar down) carries the previous pass's figures forward rather
|
|
// than overwriting them with zeroes the page would state as fact.
|
|
type LaneState struct {
|
|
Site string
|
|
Due int
|
|
LastRun time.Time
|
|
Gap time.Duration
|
|
// Checked is how many Series this pass actually read. A Lane with Series
|
|
// due and nothing checked has stopped working; one with nothing due is
|
|
// merely quiet, and the page must not draw the two the same (story 13).
|
|
Checked int
|
|
Clamped bool
|
|
Refusing bool
|
|
Browser bool
|
|
// Asleep marks a browser Lane whose last pass declined to wake Chrome
|
|
// because it was under both wake thresholds (ADR-0005). Due without
|
|
// Checked then means "waiting for the group to gather", not "stopped", and
|
|
// the page must not draw it as a stall.
|
|
Asleep 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.
|
|
// A pass that never reached the pace (Gap zero) keeps the last pass's figures:
|
|
// the Lane's due count and gap did not become zero because this pass declined
|
|
// to look, and the row's own marks say why it declined.
|
|
func (p *Poller) recordLaneState(st LaneState) {
|
|
p.mu.Lock()
|
|
defer p.mu.Unlock()
|
|
if p.laneStates == nil {
|
|
p.laneStates = make(map[string]LaneState)
|
|
}
|
|
if prev, ok := p.laneStates[st.Site]; ok && st.Gap == 0 {
|
|
st.Due, st.Gap, st.Clamped, st.Checked = prev.Due, prev.Gap, prev.Clamped, prev.Checked
|
|
}
|
|
p.laneStates[st.Site] = st
|
|
}
|