in Sources/DistributedActors/Cluster/ClusterShell+LeaderActions.swift [67:114]
func interpretLeaderActions(
_ system: ActorSystem,
_ previousState: ClusterShellState,
_ leaderActions: [ClusterShellState.LeaderAction]
) -> ClusterShellState {
guard !leaderActions.isEmpty else {
return previousState
}
var state = previousState
state.log.trace(
"Performing leader actions: \(leaderActions)",
metadata: [
"tag": "leader-action",
"leader/actions": "\(leaderActions)",
"gossip/converged": "\(state.latestGossip.converged())",
"gossip/current": "\(state.latestGossip)",
]
)
// This "dance" about collecting events first and only then emitting them is important for ordering guarantees
// with regards to the membership snapshot. We always want the snapshot to be in sync when an actor receives an update.
// The snapshot therefore MUST be updated BEFORE we emit events.
var eventsToPublish: [Cluster.Event] = []
for leaderAction in leaderActions {
switch leaderAction {
case .moveMember(let movingUp):
eventsToPublish += self.interpretMoveMemberLeaderAction(&state, movingUp: movingUp)
case .removeMember(let memberToRemove):
eventsToPublish += self.interpretRemoveMemberLeaderAction(system, &state, memberToRemove: memberToRemove)
}
}
system.cluster.updateMembershipSnapshot(state.membership)
eventsToPublish.forEach { state.events.publish($0) }
previousState.log.trace(
"Membership state after leader actions: \(state.membership)",
metadata: [
"tag": "leader-action",
"gossip/current": "\(state.latestGossip)",
"gossip/before": "\(previousState.latestGossip)",
]
)
return state
}