/
handler.go
277 lines (217 loc) · 7.38 KB
/
handler.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
package serfer
import (
"strings"
"github.com/hashicorp/serf/serf"
log "github.com/mgutz/logxi/v1"
)
const (
// StatusReap is used to update the status of a node if we
// are handling a EventMemberReap
StatusReap = serf.MemberStatus(-1)
)
// EventHandler processes generic Serf events. Depending on the
// event type, more processing may be needed.
type EventHandler interface {
HandleEvent(serf.Event)
}
// MemberEventHandler handles membership change events.
type MemberEventHandler interface {
HandleMemberEvent(serf.MemberEvent)
}
// MemberJoinHandler handles member join events.
type MemberJoinHandler interface {
HandleMemberJoin(serf.MemberEvent)
}
// MemberUpdateHandler handles member update events.
type MemberUpdateHandler interface {
HandleMemberUpdate(serf.MemberEvent)
}
// MemberLeaveHandler handles member leave events.
type MemberLeaveHandler interface {
HandleMemberLeave(serf.MemberEvent)
}
// MemberFailureHandler handles member failure events.
type MemberFailureHandler interface {
HandleMemberFailure(serf.MemberEvent)
}
// MemberReapHandler handles member reap events.
type MemberReapHandler interface {
HandleMemberReap(serf.MemberEvent)
}
// UserEventHandler handles user events.
type UserEventHandler interface {
HandleUserEvent(serf.UserEvent)
}
// UnknownEventHandler handles unknown events.
type UnknownEventHandler interface {
HandleUnknownEvent(serf.UserEvent)
}
// QueryEventHandler handles Serf query events.
type QueryEventHandler interface {
HandleQueryEvent(serf.Query)
}
// LeaderElectionHandler handles leader election events.
type LeaderElectionHandler interface {
HandleLeaderElection(serf.UserEvent)
}
// Reconciler is used to reconcile Serf events wilth an external process, like Raft.
type Reconciler interface {
Reconcile(serf.Member)
}
// IsLeaderFunc should return true if the local node is the cluster leader.
type IsLeaderFunc func() bool
// SerfEventHandler is used to dispatch various Serf events to separate event handlers.
type SerfEventHandler struct {
// ServicePrefix is used to filter out unknown events.
ServicePrefix string
// ReconcileOnJoin determines if the Reconiler is called when a node joins the cluster.
ReconcileOnJoin bool
// ReconcileOnLeave determines if the Reconiler is called when a node leaves the cluster.
ReconcileOnLeave bool
// ReconcileOnFail determines if the Reconiler is called when a node fails.
ReconcileOnFail bool
// ReconcileOnUpdate determines if the Reconiler is called when a node updates.
ReconcileOnUpdate bool
// ReconcileOnReap determines if the Reconiler is called when a node is reaped from the cluster.
ReconcileOnReap bool
// IsLeader determines if the local node is the cluster leader.
IsLeader IsLeaderFunc
// IsLeaderEventFunc determines if an event is a leader election event based on the event name.
IsLeaderEvent func(string) bool
// LeaderElectionHandler processes leader election events.
LeaderElectionHandler LeaderElectionHandler
// UserEvent processes known, non-leader election events.
UserEvent UserEventHandler
// UnknownEventHandler processes unkown events.
UnknownEventHandler UnknownEventHandler
// Called when a Member joins the cluster.
NodeJoined MemberJoinHandler
// Called when a Member leaves the cluster by sending a leave message.
NodeLeft MemberLeaveHandler
// Called when a Member has been detected as failed.
NodeFailed MemberFailureHandler
// Called when a Member has been Readed from the cluster.
NodeReaped MemberReapHandler
// Called when a Member has been updated.
NodeUpdated MemberUpdateHandler
// Called when a membership event occurs.
Reconciler Reconciler
// Called when a serf.Query is received.
QueryHandler QueryEventHandler
// Logs output
Logger log.Logger
}
// HandleEvent processes a generic Serf event and dispatches it to the appropriate
// destination.
func (s SerfEventHandler) HandleEvent(e serf.Event) {
if e == nil {
return
}
var reconcile bool
switch e.EventType() {
// If the event is a Join event, call NodeJoined and then reconcile event with
// persistent storage.
case serf.EventMemberJoin:
reconcile = s.ReconcileOnJoin
if s.NodeJoined != nil {
s.NodeJoined.HandleMemberJoin(e.(serf.MemberEvent))
}
// If the event is a Leave event, call NodeLeft and then reconcile event with
// persistent storage.
case serf.EventMemberLeave:
reconcile = s.ReconcileOnLeave
if s.NodeLeft != nil {
s.NodeLeft.HandleMemberLeave(e.(serf.MemberEvent))
}
// If the event is a Failed event, call NodeFailed and then reconcile event with
// persistent storage.
case serf.EventMemberFailed:
reconcile = s.ReconcileOnFail
if s.NodeFailed != nil {
s.NodeFailed.HandleMemberFailure(e.(serf.MemberEvent))
}
// If the event is a Reap event, reconcile event with persistent storage.
case serf.EventMemberReap:
reconcile = s.ReconcileOnReap
if s.NodeReaped != nil {
s.NodeReaped.HandleMemberReap(e.(serf.MemberEvent))
}
// If the event is a user event, handle leader elections, user events and unknown events.
case serf.EventUser:
s.handleUserEvent(e.(serf.UserEvent))
// If the event is an Update event, call NodeUpdated
case serf.EventMemberUpdate:
reconcile = s.ReconcileOnUpdate
if s.NodeUpdated != nil {
s.NodeUpdated.HandleMemberUpdate(e.(serf.MemberEvent))
}
// If the event is a query, call Query Handler
case serf.EventQuery:
if s.QueryHandler != nil {
s.QueryHandler.HandleQueryEvent(*e.(*serf.Query))
}
default:
s.Logger.Warn("unhandled Serf Event: %#v", e)
return
}
// Reconcile event with external storage
if reconcile && s.Reconciler != nil {
s.reconcile(e.(serf.MemberEvent))
}
}
// reconcile is used to reconcile Serf events with the strongly
// consistent store if we are the current leader
func (s *SerfEventHandler) reconcile(me serf.MemberEvent) {
// Do nothing if we are not the leader.
if !s.IsLeader() {
return
}
// Check if this is a reap event
isReap := me.EventType() == serf.EventMemberReap
// Queue the members for reconciliation
for _, m := range me.Members {
// Change the status if this is a reap event
if isReap {
m.Status = StatusReap
}
// Call reconcile
if s.Reconciler != nil {
s.Reconciler.Reconcile(m)
}
}
}
// handleUserEvent is called when a user event is received from both local and remote nodes.
func (s *SerfEventHandler) handleUserEvent(event serf.UserEvent) {
switch name := event.Name; {
// Handles leader election events
case s.IsLeaderEvent(name):
s.Logger.Info("serfer: New leader elected: %s", event.Payload)
// Process leader election event
if s.LeaderElectionHandler != nil {
s.LeaderElectionHandler.HandleLeaderElection(event)
}
// Handle service events
case s.isServiceEvent(name):
event.Name = s.getRawEventName(name)
s.Logger.Debug("serfer: user event: %s", event.Name)
// Process user event
if s.UserEvent != nil {
s.UserEvent.HandleUserEvent(event)
}
// Handle unknown user events
default:
s.Logger.Warn("serfer: unknown event: %v", event)
// Process unknown event
if s.UnknownEventHandler != nil {
s.UnknownEventHandler.HandleUnknownEvent(event)
}
}
}
// getRawEventName is used to get the raw event name
func (s *SerfEventHandler) getRawEventName(name string) string {
return strings.TrimPrefix(name, s.ServicePrefix+":")
}
// isServiceEvent checks if a serf event is a known event
func (s *SerfEventHandler) isServiceEvent(name string) bool {
return strings.HasPrefix(name, s.ServicePrefix+":")
}