0
# Members and Status
1
2
Member representation, status management, and member lifecycle including addressing and role-based organization. This covers how cluster nodes are represented, their lifecycle states, and how to work with member information.
3
4
## Capabilities
5
6
### Member Representation
7
8
The core representation of a cluster member containing address, status, and role information.
9
10
```scala { .api }
11
/**
12
* Represents the address, current status, and roles of a cluster member node.
13
* Note: hashCode and equals are solely based on the underlying Address, not its MemberStatus and roles.
14
*/
15
class Member private[cluster] (
16
val uniqueAddress: UniqueAddress,
17
private[cluster] val upNumber: Int,
18
val status: MemberStatus,
19
val roles: Set[String]
20
) extends Serializable {
21
/** The network address of this member */
22
def address: Address
23
24
/** Data center this member belongs to */
25
lazy val dataCenter: DataCenter
26
27
/** Check if member has specific role */
28
def hasRole(role: String): Boolean
29
30
/** Java API: get all roles as Java Set */
31
def getRoles: java.util.Set[String]
32
33
/**
34
* Is this member older, has been part of cluster longer, than another member.
35
* Only correct when comparing two existing members in a cluster.
36
* Throws IllegalArgumentException if members from different data centers.
37
*/
38
def isOlderThan(other: Member): Boolean
39
40
/** Create copy with new status */
41
def copy(status: MemberStatus): Member
42
43
/** Create copy with Up status and new up number */
44
def copyUp(upNumber: Int): Member
45
}
46
```
47
48
**Usage Examples:**
49
50
```scala
51
// Working with member information
52
cluster.state.members.foreach { member =>
53
println(s"Member: ${member.address}")
54
println(s"Status: ${member.status}")
55
println(s"Roles: ${member.roles.mkString(", ")}")
56
println(s"Data Center: ${member.dataCenter}")
57
58
// Check for specific roles
59
if (member.hasRole("frontend")) {
60
println("This is a frontend node")
61
}
62
63
if (member.hasRole("backend")) {
64
println("This is a backend node")
65
}
66
}
67
68
// Compare member ages (within same data center)
69
val members = cluster.state.members.toList
70
if (members.size >= 2) {
71
val member1 = members(0)
72
val member2 = members(1)
73
74
if (member1.dataCenter == member2.dataCenter) {
75
if (member1.isOlderThan(member2)) {
76
println(s"${member1.address} is older than ${member2.address}")
77
}
78
}
79
}
80
```
81
82
### Member Status
83
84
Enumeration of all possible member states in the cluster lifecycle.
85
86
```scala { .api }
87
/**
88
* Defines the current status of a cluster member node.
89
* Can be one of: Joining, WeaklyUp, Up, Leaving, Exiting, Down, and Removed.
90
*/
91
sealed abstract class MemberStatus
92
93
object MemberStatus {
94
/** Member is in the process of joining the cluster */
95
case object Joining extends MemberStatus
96
97
/**
98
* Member is weakly up - joined but not all nodes have seen it yet.
99
* This happens when convergence cannot be reached due to unreachable nodes.
100
*/
101
case object WeaklyUp extends MemberStatus
102
103
/** Member is fully up and participating in the cluster */
104
case object Up extends MemberStatus
105
106
/** Member is gracefully leaving the cluster */
107
case object Leaving extends MemberStatus
108
109
/** Member is in the exiting phase of leaving */
110
case object Exiting extends MemberStatus
111
112
/** Member has been marked as down (forceful removal) */
113
case object Down extends MemberStatus
114
115
/** Member has been completely removed from the cluster */
116
case object Removed extends MemberStatus
117
118
// Java API accessors
119
def joining: MemberStatus = Joining
120
def weaklyUp: MemberStatus = WeaklyUp
121
def up: MemberStatus = Up
122
def leaving: MemberStatus = Leaving
123
def exiting: MemberStatus = Exiting
124
def down: MemberStatus = Down
125
def removed: MemberStatus = Removed
126
}
127
```
128
129
**Usage Examples:**
130
131
```scala
132
import akka.cluster.MemberStatus._
133
134
// Check member status
135
cluster.state.members.foreach { member =>
136
member.status match {
137
case Joining => println(s"${member.address} is joining")
138
case WeaklyUp => println(s"${member.address} is weakly up")
139
case Up => println(s"${member.address} is up and ready")
140
case Leaving => println(s"${member.address} is leaving")
141
case Exiting => println(s"${member.address} is exiting")
142
case Down => println(s"${member.address} is down")
143
case Removed => println(s"${member.address} was removed")
144
}
145
}
146
147
// Filter members by status
148
val upMembers = cluster.state.members.filter(_.status == Up)
149
val joiningMembers = cluster.state.members.filter(_.status == Joining)
150
151
println(s"Up members: ${upMembers.size}")
152
println(s"Joining members: ${joiningMembers.size}")
153
```
154
155
### Unique Addressing
156
157
Unique addressing system that distinguishes different incarnations of nodes with the same network address.
158
159
```scala { .api }
160
/**
161
* Member identifier consisting of address and random uid.
162
* The uid is needed to be able to distinguish different
163
* incarnations of a member with same hostname and port.
164
*/
165
case class UniqueAddress(address: Address, longUid: Long) extends Ordered[UniqueAddress] {
166
/** Compare unique addresses for ordering */
167
def compare(that: UniqueAddress): Int
168
}
169
170
object UniqueAddress {
171
/** Create unique address with address and uid */
172
def apply(address: Address, uid: Long): UniqueAddress
173
}
174
```
175
176
**Usage Examples:**
177
178
```scala
179
// Access unique address information
180
val member = cluster.selfMember
181
println(s"Address: ${member.uniqueAddress.address}")
182
println(s"Unique ID: ${member.uniqueAddress.longUid}")
183
184
// Unique addresses allow distinguishing restarts
185
val addr1 = UniqueAddress(Address("akka.tcp", "System", "host", 2551), 123456L)
186
val addr2 = UniqueAddress(Address("akka.tcp", "System", "host", 2551), 789012L)
187
// Same network address but different UIDs - different incarnations
188
```
189
190
### Member Factory and Utilities
191
192
Factory methods and utilities for working with members and ordering.
193
194
```scala { .api }
195
object Member {
196
/** Empty member set constant */
197
val none: Set[Member] = Set.empty[Member]
198
199
/**
200
* Address ordering type class, sorts addresses by host and port
201
*/
202
implicit val addressOrdering: Ordering[Address]
203
204
/**
205
* Member ordering type class, sorts members by host and port
206
*/
207
implicit val ordering: Ordering[Member]
208
209
/**
210
* Sort members by age, i.e. using Member#isOlderThan.
211
* Only makes sense to compare members of same data center.
212
*/
213
val ageOrdering: Ordering[Member]
214
215
/**
216
* Picks the Member with the highest "priority" MemberStatus.
217
*/
218
def highestPriorityOf(m1: Member, m2: Member): Member
219
}
220
```
221
222
**Usage Examples:**
223
224
```scala
225
// Sort members by address
226
val sortedByAddress = cluster.state.members.toList.sorted(Member.ordering)
227
228
// Sort members by age (oldest first)
229
val membersList = cluster.state.members.toList
230
val sortedByAge = membersList.sorted(Member.ageOrdering)
231
232
// Find member with highest priority status
233
val members = List(member1, member2)
234
val highestPriority = members.reduceLeft(Member.highestPriorityOf)
235
236
// Work with empty member set
237
if (cluster.state.members == Member.none) {
238
println("No members in cluster")
239
}
240
```
241
242
### Role-Based Organization
243
244
Working with member roles for organizing cluster nodes by function.
245
246
```scala { .api }
247
// Member role methods
248
def hasRole(role: String): Boolean
249
def roles: Set[String]
250
def getRoles: java.util.Set[String] // Java API
251
252
// Cluster-level role information
253
def selfRoles: Set[String] // From Cluster class
254
def getSelfRoles: java.util.Set[String] // Java API
255
```
256
257
**Usage Examples:**
258
259
```scala
260
// Configure roles in application.conf
261
// akka.cluster.roles = ["frontend", "backend", "database"]
262
263
// Check self roles
264
println(s"My roles: ${cluster.selfRoles}")
265
266
// Find members by role
267
val frontendMembers = cluster.state.members.filter(_.hasRole("frontend"))
268
val backendMembers = cluster.state.members.filter(_.hasRole("backend"))
269
val dbMembers = cluster.state.members.filter(_.hasRole("database"))
270
271
println(s"Frontend nodes: ${frontendMembers.size}")
272
println(s"Backend nodes: ${backendMembers.size}")
273
println(s"Database nodes: ${dbMembers.size}")
274
275
// Route work based on roles
276
def routeToBackend(message: Any): Unit = {
277
val backendAddresses = cluster.state.members
278
.filter(_.hasRole("backend"))
279
.filter(_.status == Up)
280
.map(_.address)
281
282
if (backendAddresses.nonEmpty) {
283
// Send to backend nodes
284
backendAddresses.foreach { addr =>
285
// Route message to backend at addr
286
}
287
}
288
}
289
```
290
291
### Member Status Transitions
292
293
Understanding valid member status transitions and lifecycle.
294
295
```scala { .api }
296
// Status transition validation is handled internally
297
// Valid transitions:
298
// Joining -> WeaklyUp, Up, Leaving, Down, Removed
299
// WeaklyUp -> Up, Leaving, Down, Removed
300
// Up -> Leaving, Down, Removed
301
// Leaving -> Exiting, Down, Removed
302
// Down -> Removed
303
// Exiting -> Removed, Down
304
// Removed -> (no transitions - terminal state)
305
```
306
307
**Usage Examples:**
308
309
```scala
310
// Monitor member lifecycle in event handler
311
class MemberLifecycleMonitor extends Actor with ActorLogging {
312
var memberHistory = Map.empty[Address, List[MemberStatus]]
313
314
def receive = {
315
case event: MemberEvent =>
316
val member = event.member
317
val history = memberHistory.getOrElse(member.address, List.empty)
318
val newHistory = member.status :: history
319
memberHistory = memberHistory + (member.address -> newHistory)
320
321
log.info("Member {} status: {} (history: {})",
322
member.address, member.status, newHistory.reverse.mkString(" -> "))
323
324
// Detect problematic transitions
325
if (member.status == Down && history.headOption.contains(Up)) {
326
log.warning("Member {} went directly from Up to Down - possible network failure",
327
member.address)
328
}
329
}
330
}
331
```
332
333
### Data Center Support
334
335
Multi-data center clustering support for geographic distribution.
336
337
```scala { .api }
338
// Data center information
339
def dataCenter: DataCenter // From Member
340
def selfDataCenter: DataCenter // From Cluster
341
type DataCenter = String
342
343
// Data center discovery from current state
344
def allDataCenters: Set[String] // From CurrentClusterState
345
def getAllDataCenters: java.util.Set[String] // Java API
346
```
347
348
**Usage Examples:**
349
350
```scala
351
// Work with data centers
352
val state = cluster.state
353
println(s"All data centers: ${state.allDataCenters}")
354
println(s"My data center: ${cluster.selfDataCenter}")
355
356
// Organize members by data center
357
val membersByDc = cluster.state.members.groupBy(_.dataCenter)
358
membersByDc.foreach { case (dc, members) =>
359
println(s"Data center '$dc': ${members.size} members")
360
members.foreach(m => println(s" ${m.address} (${m.status})"))
361
}
362
363
// Find members in same data center
364
val sameDcMembers = cluster.state.members.filter(_.dataCenter == cluster.selfDataCenter)
365
val otherDcMembers = cluster.state.members.filter(_.dataCenter != cluster.selfDataCenter)
366
367
// Age comparison only valid within same data center
368
val myDcMembers = cluster.state.members.filter(_.dataCenter == cluster.selfDataCenter).toList
369
if (myDcMembers.size >= 2) {
370
try {
371
val oldest = myDcMembers.minBy(_.upNumber)
372
println(s"Oldest member in my DC: ${oldest.address}")
373
} catch {
374
case _: IllegalArgumentException =>
375
println("Cannot compare members from different data centers")
376
}
377
}
378
```
379
380
## Types
381
382
```scala { .api }
383
// Core member types
384
class Member(uniqueAddress: UniqueAddress, status: MemberStatus, roles: Set[String])
385
case class UniqueAddress(address: Address, longUid: Long)
386
type DataCenter = String
387
388
// Member status enumeration
389
sealed abstract class MemberStatus
390
case object Joining extends MemberStatus
391
case object WeaklyUp extends MemberStatus
392
case object Up extends MemberStatus
393
case object Leaving extends MemberStatus
394
case object Exiting extends MemberStatus
395
case object Down extends MemberStatus
396
case object Removed extends MemberStatus
397
398
// Ordering types
399
implicit val addressOrdering: Ordering[Address]
400
implicit val ordering: Ordering[Member]
401
val ageOrdering: Ordering[Member]
402
```