remote_notice.go RawHistoryFolder
1package domain
2
3// Failing reports an availability that cannot serve sessions right now.
4func (a RemoteAvailability) Failing() bool {
5 switch a {
6 case RemoteAvailabilityUnreachable, RemoteAvailabilityAuthFailed,
7 RemoteAvailabilityInvalidResponse, RemoteAvailabilityNoDaemon,
8 RemoteAvailabilityIncompatible:
9 return true
10 default:
11 return false
12 }
13}
14
15// RemoteHealth is the notice-relevant state of one observed remote host.
16type RemoteHealth struct {
17 Availability RemoteAvailability
18 VersionMismatch bool
19 // Episode increments on each new failure episode.
20 Episode uint64
21}
22
23// Failing reports a host that cannot serve sessions right now.
24func (h RemoteHealth) Failing() bool {
25 return h.VersionMismatch || h.Availability.Failing()
26}
27
28func (h RemoteHealth) healthy() bool {
29 return h.Availability == RemoteAvailabilityReachable && !h.VersionMismatch
30}
31
32// settled reports a state worth remembering: in-between states (unknown,
33// checking) keep the last settled one so a later recovery is still seen.
34func (h RemoteHealth) settled() bool {
35 return h.Failing() || h.Availability == RemoteAvailabilityReachable
36}
37
38// RemoteHealthEvent is what one host transition is worth telling the user.
39type RemoteHealthEvent uint8
40
41const (
42 RemoteHealthSilent RemoteHealthEvent = iota
43 // RemoteHealthFailed is a new failure episode or a new failure class.
44 RemoteHealthFailed
45 // RemoteHealthRecovered is a host serving again after a real failure.
46 RemoteHealthRecovered
47)
48
49// RemoteHealthTransition judges one host observation against the last
50// remembered state (seen is false when there is none). It returns the state
51// to remember and the event worth one notice. Ordinary progress (checking,
52// first sighting of a healthy host) is silent. A host whose daemon just
53// started after "no daemon" was never disconnected, so it is silent too.
54func RemoteHealthTransition(prev RemoteHealth, seen bool, cur RemoteHealth) (RemoteHealth, RemoteHealthEvent) {
55 next := cur
56 if seen && !cur.settled() {
57 next = prev
58 }
59 switch {
60 case cur.Failing():
61 if seen && prev.Failing() && prev.Episode == cur.Episode && prev.Availability == cur.Availability {
62 return next, RemoteHealthSilent
63 }
64 return next, RemoteHealthFailed
65 case seen && prev.Failing() && prev.Availability != RemoteAvailabilityNoDaemon && cur.healthy():
66 return next, RemoteHealthRecovered
67 default:
68 return next, RemoteHealthSilent
69 }
70}