-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathserver.go
136 lines (106 loc) · 3.41 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package loadbalancer
import (
"time"
)
// -----------------------------------------------------------------------------
// Server represents an upstream server in a load balancer.
type Server struct {
lb *LoadBalancer // NOTE: Go's Mark & Sweep plays well with this circular reference
opts ServerOptions
index int
isDown bool
failCounter int
// NOTE: failTimestamp has two uses:
// 1. Marks the timestamp of the first access failure
// 2. Marks the timestamp to put it again online when down
failTimestamp time.Time
userData interface{}
}
// ServerOptions specifies the weight, fail timeout and other options of a server.
type ServerOptions struct {
// Weight
Weight int
// Maximum amount of unsuccessful attempts to reach the server that must happen in the time frame specified by the
// FailTimeout parameter before setting it offline. The FailTimeout must be also specified. A value of zero
// means the server will never go offline.
MaxFails int
// Fail timeout sets the time period where MaxFails unsuccessful attempts must happen in order to set a server
// offline. Once the server becomes offline, MaxFails indicates how much time should pass before putting the server
// online again.
FailTimeout time.Duration
// Indicates if this server must be used as a backup fail over. Backup servers never goes offline.
IsBackup bool
}
// ServerGroup is a group of servers. Used to classify and track primary and backup servers.
type ServerGroup struct {
srvList []Server
currServerIdx int
currServerWeight int
}
// -----------------------------------------------------------------------------
// UserData returns the server user data
func (srv *Server) UserData() interface{} {
return srv.userData
}
// SetOnline marks a server as available
func (srv *Server) SetOnline() {
// We only can change the online/offline status on primary servers
if srv.opts.MaxFails == 0 || srv.opts.IsBackup {
return
}
notifyUp := false
// Lock access
srv.lb.mtx.Lock()
// Reset the failure counter
srv.failCounter = 0
// If the server was marked as down, put it online again
if srv.isDown {
srv.isDown = false
srv.lb.primaryOnlineCount += 1
notifyUp = true
}
// Unlock access
srv.lb.mtx.Unlock()
// Call event callback
if notifyUp {
srv.lb.raiseEvent(ServerUpEvent, srv)
}
}
// SetOffline marks a server as unavailable
func (srv *Server) SetOffline() {
// We only can change the online/offline status on primary servers
if srv.opts.MaxFails == 0 || srv.opts.IsBackup {
return
}
notifyDown := false
// Lock access
srv.lb.mtx.Lock()
// If server is up
if !srv.isDown && srv.failCounter < srv.opts.MaxFails {
now := time.Now()
// Increment the failure counter
srv.failCounter += 1
if srv.failCounter == 1 {
// If it is the first failure, set the fail timestamp limit
srv.failTimestamp = now.Add(srv.opts.FailTimeout)
} else {
// If this failure passed after the fail timeout, reset the counter
if now.After(srv.failTimestamp) {
srv.failCounter = 1
}
}
// If we reach to the maximum failure count, put this server offline
if srv.failCounter == srv.opts.MaxFails {
srv.isDown = true
srv.failTimestamp = now.Add(srv.opts.FailTimeout)
srv.lb.primaryOnlineCount -= 1
notifyDown = true
}
}
// Unlock access
srv.lb.mtx.Unlock()
// Call event callback
if notifyDown {
srv.lb.raiseEvent(ServerDownEvent, srv)
}
}