0
# Member Management
1
2
Member management in Akka Cluster centers around the `Member` class which represents cluster nodes and their current state. Members progress through well-defined lifecycle stages and can be organized by roles and data centers.
3
4
## Member Representation
5
6
### Member Class
7
8
```scala { .api }
9
class Member private[cluster] (
10
val uniqueAddress: UniqueAddress,
11
private[cluster] val upNumber: Int,
12
val status: MemberStatus,
13
val roles: Set[String],
14
val appVersion: Version
15
) extends Serializable {
16
def address: Address
17
def dataCenter: DataCenter
18
def hasRole(role: String): Boolean
19
def getRoles: java.util.Set[String]
20
def isOlderThan(other: Member): Boolean
21
def copy(status: MemberStatus): Member
22
def copyUp(upNumber: Int): Member
23
24
// Standard methods
25
override def hashCode: Int
26
override def equals(other: Any): Boolean
27
override def toString: String
28
}
29
```
30
31
### Unique Address
32
33
```scala { .api }
34
class UniqueAddress(val address: Address, val longUid: Long)
35
extends Product with Serializable with Ordered[UniqueAddress] {
36
def address: Address
37
def longUid: Long
38
39
@deprecated("Use longUid instead", since = "2.4.11")
40
def uid: Int = longUid.toInt
41
42
def compare(that: UniqueAddress): Int
43
override def productArity: Int = 2
44
override def productElement(n: Int): Any
45
override def canEqual(that: Any): Boolean
46
override def hashCode: Int
47
override def equals(other: Any): Boolean
48
override def toString: String
49
}
50
```
51
52
### Member Properties
53
54
```scala
55
val member: Member = cluster.selfMember
56
57
// Core identification
58
val address: Address = member.address // Network address
59
val uniqueAddress: UniqueAddress = member.uniqueAddress // Address + unique ID
60
val uid: Long = member.uniqueAddress.uid // Unique identifier
61
62
// Member metadata
63
val status: MemberStatus = member.status // Current lifecycle status
64
val roles: Set[String] = member.roles // Assigned roles
65
val dataCenter: String = member.dataCenter // Data center assignment
66
val appVersion: Version = member.appVersion // Application version
67
68
println(s"Member: ${address}, Status: ${status}, DC: ${dataCenter}")
69
```
70
71
## Member Status Lifecycle
72
73
### Status Enumeration
74
75
```scala { .api }
76
sealed abstract class MemberStatus
77
78
case object Joining extends MemberStatus
79
case object WeaklyUp extends MemberStatus
80
case object Up extends MemberStatus
81
case object Leaving extends MemberStatus
82
case object Exiting extends MemberStatus
83
case object Down extends MemberStatus
84
case object Removed extends MemberStatus
85
case object PreparingForShutdown extends MemberStatus
86
case object ReadyForShutdown extends MemberStatus
87
88
object MemberStatus {
89
// Java API accessors
90
def joining(): MemberStatus = Joining
91
def weaklyUp(): MemberStatus = WeaklyUp
92
def up(): MemberStatus = Up
93
def leaving(): MemberStatus = Leaving
94
def exiting(): MemberStatus = Exiting
95
def down(): MemberStatus = Down
96
def removed(): MemberStatus = Removed
97
def shuttingDown(): MemberStatus = PreparingForShutdown // Java name mapping
98
def shutDown(): MemberStatus = ReadyForShutdown // Java name mapping
99
}
100
```
101
102
### Status Transitions
103
104
Normal lifecycle progression:
105
```
106
Joining → WeaklyUp → Up → Leaving → Exiting → Removed
107
```
108
109
Failure scenarios:
110
```
111
Any Status → Down → Removed
112
```
113
114
Coordinated shutdown:
115
```
116
Up → PreparingForShutdown → ReadyForShutdown → Exiting → Removed
117
```
118
119
Complete allowed transitions:
120
```
121
From PreparingForShutdown: ReadyForShutdown, Removed, Leaving, Down
122
From ReadyForShutdown: Removed, Leaving, Down
123
```
124
125
### Status Descriptions
126
127
- **Joining**: Node is attempting to join cluster
128
- **WeaklyUp**: Node is up but cluster hasn't reached minimum size
129
- **Up**: Node is fully operational cluster member
130
- **Leaving**: Node is gracefully leaving cluster
131
- **Exiting**: Node is in exit process, will be removed
132
- **Down**: Node marked as failed/unreachable
133
- **Removed**: Node completely removed from cluster
134
- **PreparingForShutdown**: Node preparing for coordinated shutdown
135
- **ReadyForShutdown**: Node ready for coordinated shutdown
136
137
## Role-Based Operations
138
139
### Role Assignment
140
141
Roles are configured during system startup and cannot be changed at runtime:
142
143
```hocon
144
akka.cluster.roles = ["frontend", "backend", "database"]
145
```
146
147
### Role Checking
148
149
```scala
150
val member: Member = cluster.selfMember
151
152
// Check for specific role
153
if (member.hasRole("backend")) {
154
// Backend-specific logic
155
startBackendServices()
156
}
157
158
// Check multiple roles
159
val isFrontend = member.hasRole("frontend")
160
val isDatabase = member.hasRole("database")
161
162
// Get all roles
163
val allRoles: Set[String] = member.roles
164
println(s"Node roles: ${allRoles.mkString(", ")}")
165
166
// Java API
167
val rolesJava: java.util.Set[String] = member.getRoles
168
```
169
170
### Role-Based Member Filtering
171
172
```scala
173
val currentState = cluster.state
174
175
// Find all backend members
176
val backendMembers = currentState.members.filter(_.hasRole("backend"))
177
178
// Find available (Up or WeaklyUp) frontend members
179
val availableFrontends = currentState.members
180
.filter(m => m.hasRole("frontend") &&
181
(m.status == MemberStatus.Up || m.status == MemberStatus.WeaklyUp))
182
183
// Count members by role
184
val membersByRole = currentState.members.groupBy(_.roles).view.mapValues(_.size)
185
println(s"Members by role: $membersByRole")
186
```
187
188
## Member Comparison and Ordering
189
190
### Age Comparison
191
192
```scala { .api }
193
// Compare member age (same data center only)
194
def isOlderThan(other: Member): Boolean
195
```
196
197
Usage:
198
```scala
199
val member1: Member = // ...
200
val member2: Member = // ...
201
202
try {
203
if (member1.isOlderThan(member2)) {
204
println(s"${member1.address} is older than ${member2.address}")
205
}
206
} catch {
207
case _: IllegalArgumentException =>
208
println("Cannot compare members from different data centers")
209
}
210
```
211
212
### Member Ordering
213
214
```scala { .api }
215
object Member {
216
val ordering: Ordering[Member]
217
val ageOrdering: Ordering[Member]
218
val addressOrdering: Ordering[Address]
219
val none: Set[Member]
220
221
// Utility methods
222
def highestPriorityOf(m1: Member, m2: Member): Member
223
}
224
```
225
226
Usage:
227
```scala
228
val members: Set[Member] = cluster.state.members.toSet
229
230
// Default ordering (by address)
231
val sortedMembers = members.toSeq.sorted(Member.ordering)
232
233
// Age-based ordering (oldest first)
234
val membersByAge = members.toSeq.sorted(Member.ageOrdering)
235
236
// Address-based ordering
237
val addresses = members.map(_.address).toSeq.sorted(Member.addressOrdering)
238
```
239
240
## Data Center Support
241
242
### Data Center Assignment
243
244
Data centers are assigned via special roles with the `dc-` prefix:
245
246
```hocon
247
akka.cluster {
248
roles = ["dc-east", "backend"]
249
multi-data-center.self-data-center = "east"
250
}
251
```
252
253
### Data Center Operations
254
255
```scala
256
val member: Member = cluster.selfMember
257
258
// Get data center
259
val dataCenter: String = member.dataCenter
260
println(s"Member data center: $dataCenter")
261
262
// Filter by data center
263
val currentState = cluster.state
264
val localMembers = currentState.members.filter(_.dataCenter == cluster.selfDataCenter)
265
val remoteMembers = currentState.members.filter(_.dataCenter != cluster.selfDataCenter)
266
267
// Group by data center
268
val membersByDC = currentState.members.groupBy(_.dataCenter)
269
membersByDC.foreach { case (dc, members) =>
270
println(s"Data center '$dc': ${members.size} members")
271
}
272
```
273
274
## Member State Changes
275
276
### Creating Member Copies
277
278
```scala { .api }
279
def copy(status: MemberStatus): Member
280
def copyUp(upNumber: Int): Member
281
```
282
283
Usage (typically internal to Akka):
284
```scala
285
val member: Member = // existing member
286
val updatedMember = member.copy(MemberStatus.Up)
287
val upMember = member.copyUp(upNumber = 42)
288
```
289
290
### Allowed Status Transitions
291
292
Only specific status transitions are allowed:
293
- From `Joining` to `WeaklyUp` or `Up`
294
- From `WeaklyUp` to `Up`
295
- From `Up` to `Leaving` or `Down` or `PreparingForShutdown`
296
- From `Leaving` to `Exiting` or `Down`
297
- From `Exiting` to `Removed`
298
- From `Down` to `Removed`
299
- From `PreparingForShutdown` to `ReadyForShutdown` or `Down`
300
- From `ReadyForShutdown` to `Exiting` or `Down`
301
302
## Application Version Management
303
304
### Version Compatibility
305
306
Members carry application version information for compatibility checking:
307
308
```scala
309
val member: Member = cluster.selfMember
310
val version: Version = member.appVersion
311
312
println(s"App version: ${version.version}")
313
314
// Version comparison (if needed)
315
val otherVersion = Version("1.2.0")
316
if (version >= otherVersion) {
317
// Compatible version
318
}
319
```
320
321
### Dynamic Version Setting
322
323
```scala
324
import scala.concurrent.Future
325
import akka.util.Version
326
327
// Set version before joining
328
val versionFuture: Future[Version] = loadVersionFromExternalSystem()
329
cluster.setAppVersionLater(versionFuture)
330
cluster.joinSeedNodes(seedNodes)
331
```
332
333
## Member Information Access
334
335
### Self Member Access
336
337
```scala
338
val cluster = Cluster(system)
339
340
// Current node as member
341
val selfMember: Member = cluster.selfMember
342
val selfAddress: Address = cluster.selfAddress
343
val selfUniqueAddress: UniqueAddress = cluster.selfUniqueAddress
344
val selfRoles: Set[String] = cluster.selfRoles
345
val selfDataCenter: String = cluster.selfDataCenter
346
347
// Java API for roles
348
val selfRolesJava: java.util.Set[String] = cluster.getSelfRoles
349
```
350
351
### Cluster Member Access
352
353
```scala
354
val state: CurrentClusterState = cluster.state
355
356
// All members
357
val allMembers: immutable.SortedSet[Member] = state.members
358
359
// Filter by status
360
val upMembers = allMembers.filter(_.status == MemberStatus.Up)
361
val joiningMembers = allMembers.filter(_.status == MemberStatus.Joining)
362
363
// Find specific member
364
val memberOpt = allMembers.find(_.address == targetAddress)
365
366
// Unreachable members
367
val unreachableMembers: Set[Member] = state.unreachable
368
```
369
370
## Member Lifecycle Monitoring
371
372
### Complete Member Tracking Example
373
374
```scala
375
import akka.actor.{Actor, ActorLogging}
376
import akka.cluster.{Cluster, Member, MemberStatus}
377
import akka.cluster.ClusterEvent._
378
import scala.collection.mutable
379
380
class MemberTracker extends Actor with ActorLogging {
381
val cluster = Cluster(context.system)
382
val members = mutable.Map[Address, Member]()
383
384
override def preStart(): Unit = {
385
cluster.subscribe(self, classOf[MemberEvent])
386
}
387
388
override def postStop(): Unit = {
389
cluster.unsubscribe(self)
390
}
391
392
def receive = {
393
case state: CurrentClusterState =>
394
members.clear()
395
state.members.foreach { member =>
396
members(member.address) = member
397
logMemberInfo(member, "Initial")
398
}
399
400
case MemberJoined(member) =>
401
members(member.address) = member
402
logMemberInfo(member, "Joined")
403
404
case MemberUp(member) =>
405
members(member.address) = member
406
logMemberInfo(member, "Up")
407
408
case MemberLeft(member) =>
409
members(member.address) = member
410
logMemberInfo(member, "Left")
411
412
case MemberRemoved(member, previousStatus) =>
413
members.remove(member.address)
414
log.info("Member removed: {} (was: {})", member.address, previousStatus)
415
416
case event: MemberEvent =>
417
members(event.member.address) = event.member
418
logMemberInfo(event.member, event.getClass.getSimpleName)
419
}
420
421
def logMemberInfo(member: Member, event: String): Unit = {
422
log.info("{}: {} - Status: {}, Roles: {}, DC: {}, Version: {}",
423
event, member.address, member.status,
424
member.roles.mkString(","), member.dataCenter, member.appVersion)
425
}
426
}
427
```