-
Notifications
You must be signed in to change notification settings - Fork 80
Make ClusterControl.membershipSnapshot async property #969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
a74ceca
09ca1d2
c5e1e0c
3efd08f
c6f651c
ccf4c3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| import Distributed | ||
| import DistributedActorsConcurrencyHelpers | ||
| import Logging | ||
| import NIO | ||
|
|
@@ -42,37 +43,62 @@ public struct ClusterControl { | |
| /// of obtaining the information to act on rather than mixing the two. Use events if transitions state should trigger | ||
| /// something, and use the snapshot for ad-hoc "one time" membership inspections. | ||
| public var membershipSnapshot: Cluster.Membership { | ||
| self.membershipSnapshotLock.lock() | ||
| defer { self.membershipSnapshotLock.unlock() } | ||
| return self._membershipSnapshotHolder.membership | ||
| get async throws { | ||
| try await self._membershipSnapshotHolder.get() | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sweet :) |
||
|
|
||
| internal func updateMembershipSnapshot(_ snapshot: Cluster.Membership) { | ||
| self.membershipSnapshotLock.lock() | ||
| defer { self.membershipSnapshotLock.unlock() } | ||
| self._membershipSnapshotHolder.membership = snapshot | ||
| Task { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure about usages of |
||
| try await self._membershipSnapshotHolder.update(snapshot) | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah that's probably fine to be honest |
||
| } | ||
|
|
||
| private let membershipSnapshotLock: Lock | ||
| private let _membershipSnapshotHolder: MembershipHolder | ||
| private class MembershipHolder { | ||
| internal distributed actor MembershipHolder { | ||
|
||
| typealias ActorSystem = ClusterSystem | ||
|
|
||
| static let path: ActorPath = try! ActorPath._system.appending(segment: ActorPathSegment("clusterMembership")) | ||
|
|
||
| static var props: _Props { | ||
| var ps = _Props() | ||
| ps._knownActorName = Self.path.name | ||
| ps._systemActor = true | ||
| ps._wellKnown = true | ||
| return ps | ||
| } | ||
|
|
||
| var membership: Cluster.Membership | ||
| init(membership: Cluster.Membership) { | ||
|
|
||
| init(membership: Cluster.Membership, actorSystem: ActorSystem) { | ||
| self.actorSystem = actorSystem | ||
| self.membership = membership | ||
| } | ||
|
|
||
| distributed func get() -> Cluster.Membership { | ||
| self.membership | ||
| } | ||
|
|
||
| distributed func update(_ membership: Cluster.Membership) { | ||
| self.membership = membership | ||
| } | ||
|
|
||
| distributed func join(_ node: UniqueNode) { | ||
| _ = self.membership.join(node) | ||
| } | ||
| } | ||
|
|
||
| internal let ref: ClusterShell.Ref | ||
|
|
||
| init(_ settings: ClusterSystemSettings, clusterRef: ClusterShell.Ref, eventStream: EventStream<Cluster.Event>) { | ||
| init(_ settings: ClusterSystemSettings, clusterRef: ClusterShell.Ref, membership: MembershipHolder, eventStream: EventStream<Cluster.Event>) { | ||
| self.settings = settings | ||
| self.ref = clusterRef | ||
| self.events = eventStream | ||
|
|
||
| let membershipSnapshotLock = Lock() | ||
| self.membershipSnapshotLock = membershipSnapshotLock | ||
| self._membershipSnapshotHolder = MembershipHolder(membership: .empty) | ||
| _ = self._membershipSnapshotHolder.membership.join(settings.uniqueBindNode) | ||
| self._membershipSnapshotHolder = membership | ||
| Task { | ||
| try await membership.join(settings.uniqueBindNode) | ||
| } | ||
| } | ||
|
|
||
| /// The node value representing _this_ node in the cluster. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -314,7 +314,10 @@ public class ClusterSystem: DistributedActorSystem, @unchecked Sendable { | |
| ) | ||
|
|
||
| _ = self._clusterStore.storeIfNilThenLoad(Box(nil)) | ||
| _ = self._clusterControlStore.storeIfNilThenLoad(Box(ClusterControl(settings, clusterRef: self.deadLetters.adapted(), eventStream: clusterEvents))) | ||
| await _Props.$forSpawn.withValue(ClusterControl.MembershipHolder.props) { | ||
| let membership = ClusterControl.MembershipHolder(membership: .empty, actorSystem: self) | ||
| _ = self._clusterControlStore.storeIfNilThenLoad(Box(ClusterControl(settings, clusterRef: self.deadLetters.adapted(), membership: membership, eventStream: clusterEvents))) | ||
| } | ||
| } | ||
|
|
||
| // node watcher MUST be prepared before receptionist (or any other actor) because it (and all actors) need it if we're running clustered | ||
|
|
@@ -331,7 +334,10 @@ public class ClusterSystem: DistributedActorSystem, @unchecked Sendable { | |
| customBehavior: ClusterEventStream.Shell.behavior | ||
| ) | ||
| let clusterRef = try! cluster.start(system: self, clusterEvents: clusterEvents) // only spawns when cluster is initialized | ||
| _ = self._clusterControlStore.storeIfNilThenLoad(Box(ClusterControl(settings, clusterRef: clusterRef, eventStream: clusterEvents))) | ||
| await _Props.$forSpawn.withValue(ClusterControl.MembershipHolder.props) { | ||
| let membership = ClusterControl.MembershipHolder(membership: .empty, actorSystem: self) | ||
| _ = self._clusterControlStore.storeIfNilThenLoad(Box(ClusterControl(settings, clusterRef: clusterRef, membership: membership, eventStream: clusterEvents))) | ||
| } | ||
|
|
||
| self._associationTombstoneCleanupTask = eventLoopGroup.next().scheduleRepeatedTask( | ||
| initialDelay: settings.associationTombstoneCleanupInterval.toNIO, | ||
|
|
@@ -491,8 +497,10 @@ public class ClusterSystem: DistributedActorSystem, @unchecked Sendable { | |
| self.shutdownSemaphore.wait() | ||
|
|
||
| /// Down this member as part of shutting down; it may have enough time to notify other nodes on an best effort basis. | ||
| if let myselfMember = self.cluster.membershipSnapshot.uniqueMember(self.cluster.uniqueNode) { | ||
| self.cluster.down(member: myselfMember) | ||
| Task { | ||
| if let myselfMember = try await self.cluster.membershipSnapshot.uniqueMember(self.cluster.uniqueNode) { | ||
| self.cluster.down(member: myselfMember) | ||
| } | ||
| } | ||
|
||
|
|
||
| self.settings.plugins.stopAll(self) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.