@@ -13,8 +13,19 @@ type LoadBalancer struct {
1313 primaryGroup ServerGroup
1414 backupGroup ServerGroup
1515 primaryOnlineCount int
16+ eventHandlerMtx sync.RWMutex
17+ eventHandler EventHandler
1618}
1719
20+ type EventHandler func (eventType int , server * Server )
21+
22+ // -----------------------------------------------------------------------------
23+
24+ const (
25+ ServerUpEvent int = iota + 1
26+ ServerDownEvent
27+ )
28+
1829const (
1930 InvalidParamsErr = "invalid parameter"
2031)
@@ -31,18 +42,30 @@ func Create() *LoadBalancer {
3142 backupGroup : ServerGroup {
3243 srvList : make ([]Server , 0 ),
3344 },
45+ eventHandlerMtx : sync.RWMutex {},
3446 }
3547 return & lb
3648}
3749
50+ // SetEventHandler sets a new notification handler callback
51+ func (lb * LoadBalancer ) SetEventHandler (handler EventHandler ) {
52+ lb .eventHandlerMtx .Lock ()
53+ lb .eventHandler = handler
54+ lb .eventHandlerMtx .Unlock ()
55+ }
56+
3857// Add adds a new server to the list
3958func (lb * LoadBalancer ) Add (opts ServerOptions , userData interface {}) error {
4059 // Check options
4160 if opts .Weight < 0 {
4261 return errors .New (InvalidParamsErr )
4362 }
4463 if ! opts .IsBackup {
45- if opts .MaxFails < 0 || opts .FailTimeout <= time .Duration (0 ) {
64+ if opts .MaxFails > 0 {
65+ if opts .FailTimeout <= time .Duration (0 ) {
66+ return errors .New (InvalidParamsErr )
67+ }
68+ } else if opts .MaxFails < 0 {
4669 return errors .New (InvalidParamsErr )
4770 }
4871 }
@@ -56,7 +79,7 @@ func (lb *LoadBalancer) Add(opts ServerOptions, userData interface{}) error {
5679 if srv .opts .Weight == 0 {
5780 srv .opts .Weight = 1
5881 }
59- if opts .IsBackup {
82+ if opts .IsBackup || srv . opts . MaxFails == 0 {
6083 srv .opts .MaxFails = 0
6184 srv .opts .FailTimeout = time .Duration (0 )
6285 }
@@ -89,21 +112,27 @@ func (lb *LoadBalancer) Add(opts ServerOptions, userData interface{}) error {
89112
90113// Next gets the next available server. It can return nil if no available server
91114func (lb * LoadBalancer ) Next () * Server {
115+ var nextServer * Server
116+
92117 now := time .Now ()
93118
119+ notifyUp := make ([]* Server , 0 ) // NOTE: We would use defer, but they are executed LIFO
120+
94121 // Lock access
95122 lb .mtx .Lock ()
96- defer lb .mtx .Unlock ()
97123
98124 // If all primary servers are offline, check if we can put someone up
99125 if lb .primaryOnlineCount == 0 {
100126 for idx := range lb .primaryGroup .srvList {
101- if now .After (lb .primaryGroup .srvList [idx ].failTimestamp ) {
102- // Put this server online again
103- lb .primaryGroup .srvList [idx ].isDown = false
104- lb .primaryGroup .srvList [idx ].failCounter = 0
127+ srv := & lb .primaryGroup .srvList [idx ]
105128
129+ if now .After (srv .failTimestamp ) {
130+ // Put this server online again
131+ srv .isDown = false
132+ srv .failCounter = 0
106133 lb .primaryOnlineCount += 1
134+
135+ notifyUp = append (notifyUp , srv )
107136 }
108137 }
109138 }
@@ -117,14 +146,17 @@ func (lb *LoadBalancer) Next() *Server {
117146 // Set this server online again
118147 srv .isDown = false
119148 srv .lb .primaryOnlineCount += 1
149+
150+ notifyUp = append (notifyUp , srv )
120151 }
121152
122153 if ! srv .isDown && lb .primaryGroup .currServerWeight < srv .opts .Weight {
123154 // Got a server!
124155 lb .primaryGroup .currServerWeight += 1
125156
126- // Done
127- return srv
157+ // Select this server
158+ nextServer = srv
159+ break
128160 }
129161
130162 // Advance to next server
@@ -137,17 +169,18 @@ func (lb *LoadBalancer) Next() *Server {
137169 }
138170 }
139171
140- // If we reach here, there is no primary server available
141- if len (lb .backupGroup .srvList ) > 0 {
172+ // Look for backup servers if there is no primary available
173+ if nextServer == nil && len (lb .backupGroup .srvList ) > 0 {
142174 for {
143175 srv := & lb .backupGroup .srvList [lb .backupGroup .currServerIdx ]
144176
145177 if lb .backupGroup .currServerWeight < srv .opts .Weight {
146178 // Got a server!
147179 lb .backupGroup .currServerWeight += 1
148180
149- // Done
150- return srv
181+ // Select this server
182+ nextServer = srv
183+ break
151184 }
152185
153186 // Advance to next server
@@ -160,8 +193,16 @@ func (lb *LoadBalancer) Next() *Server {
160193 }
161194 }
162195
163- // No available server
164- return nil
196+ // Unlock access
197+ lb .mtx .Unlock ()
198+
199+ // Call event callback
200+ for _ , srv := range notifyUp {
201+ lb .raiseEvent (ServerUpEvent , srv )
202+ }
203+
204+ // Done
205+ return nextServer
165206}
166207
167208// WaitNext returns a channel that is fulfilled with the next available server
@@ -227,3 +268,14 @@ func (lb *LoadBalancer) WaitNext() (ch chan *Server) {
227268
228269 return
229270}
271+
272+ // -----------------------------------------------------------------------------
273+ // Private methods
274+
275+ func (lb * LoadBalancer ) raiseEvent (eventType int , server * Server ) {
276+ lb .eventHandlerMtx .RLock ()
277+ if lb .eventHandler != nil {
278+ lb .eventHandler (eventType , server )
279+ }
280+ lb .eventHandlerMtx .RUnlock ()
281+ }
0 commit comments