Skip to content

Commit 91479d6

Browse files
committed
Add lock
1 parent 2c23474 commit 91479d6

File tree

3 files changed

+36
-22
lines changed

3 files changed

+36
-22
lines changed

Sources/ActorSingletonPlugin/ActorSingleton.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import DistributedActors
16+
import DistributedActorsConcurrencyHelpers
1617

1718
// ==== ----------------------------------------------------------------------------------------------------------------
1819
// MARK: Actor singleton
@@ -28,7 +29,14 @@ internal final class ActorSingleton<Message> {
2829
let behavior: Behavior<Message>?
2930

3031
/// The `ActorSingletonProxy` ref
31-
internal private(set) var proxy: ActorRef<Message>?
32+
private var _proxy: ActorRef<Message>?
33+
private let proxyLock = Lock()
34+
35+
internal var proxy: ActorRef<Message>? {
36+
self.proxyLock.withLock {
37+
self._proxy
38+
}
39+
}
3240

3341
init(settings: ActorSingletonSettings, props: Props?, _ behavior: Behavior<Message>?) {
3442
self.settings = settings
@@ -39,11 +47,13 @@ internal final class ActorSingleton<Message> {
3947
/// Spawns `ActorSingletonProxy` and associated actors (e.g., `ActorSingletonManager`).
4048
func spawnAll(_ system: ActorSystem) throws {
4149
let allocationStrategy = self.settings.allocationStrategy.make(system.settings.cluster, self.settings)
42-
self.proxy = try system._spawnSystemActor(
43-
"singletonProxy-\(self.settings.name)",
44-
ActorSingletonProxy(settings: self.settings, allocationStrategy: allocationStrategy, props: self.props, self.behavior).behavior,
45-
props: ._wellKnown
46-
)
50+
try self.proxyLock.withLock {
51+
self._proxy = try system._spawnSystemActor(
52+
"singletonProxy-\(self.settings.name)",
53+
ActorSingletonProxy(settings: self.settings, allocationStrategy: allocationStrategy, props: self.props, self.behavior).behavior,
54+
props: ._wellKnown
55+
)
56+
}
4757
}
4858
}
4959

Sources/ActorSingletonPlugin/ActorSingletonPlugin.swift

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
//===----------------------------------------------------------------------===//
1414

1515
import DistributedActors
16+
import DistributedActorsConcurrencyHelpers
1617

1718
// ==== ----------------------------------------------------------------------------------------------------------------
1819
// MARK: Actor singleton plugin
@@ -31,26 +32,29 @@ import DistributedActors
3132
/// and <a href="https://doc.akka.io/docs/akka/current/cluster-singleton.html">`ClusterSingleton` in Akka</a>.
3233
public final class ActorSingletonPlugin {
3334
private var singletons: [String: BoxedActorSingleton] = [:]
35+
private let singletonsLock = Lock()
3436

3537
public init() {}
3638

3739
func ref<Message>(of type: Message.Type, settings: ActorSingletonSettings, system: ActorSystem, props: Props? = nil, _ behavior: Behavior<Message>? = nil) throws -> ActorRef<Message> {
38-
if let existing = self.singletons[settings.name] {
39-
guard let proxy = existing.unsafeUnwrapAs(Message.self).proxy else {
40-
fatalError("Singleton [\(settings.name)] not yet initialized")
40+
try self.singletonsLock.withLock {
41+
if let existing = self.singletons[settings.name] {
42+
guard let proxy = existing.unsafeUnwrapAs(Message.self).proxy else {
43+
fatalError("Singleton [\(settings.name)] not yet initialized")
44+
}
45+
return proxy
4146
}
42-
return proxy
43-
}
4447

45-
let singleton = ActorSingleton<Message>(settings: settings, props: props, behavior)
46-
try singleton.spawnAll(system)
47-
self.singletons[settings.name] = BoxedActorSingleton(singleton)
48+
let singleton = ActorSingleton<Message>(settings: settings, props: props, behavior)
49+
try singleton.spawnAll(system)
50+
self.singletons[settings.name] = BoxedActorSingleton(singleton)
4851

49-
guard let proxy = singleton.proxy else {
50-
fatalError("Singleton[\(settings.name)] not yet initialized")
51-
}
52+
guard let proxy = singleton.proxy else {
53+
fatalError("Singleton[\(settings.name)] not yet initialized")
54+
}
5255

53-
return proxy // FIXME: Worried that we never synchronize access to proxy...
56+
return proxy
57+
}
5458
}
5559

5660
func actor<Act: Actorable>(of type: Act.Type, settings: ActorSingletonSettings, system: ActorSystem, props: Props? = nil, _ makeInstance: ((Actor<Act>.Context) -> Act)? = nil) throws -> Actor<Act> {
@@ -92,8 +96,10 @@ extension ActorSingletonPlugin: Plugin {
9296

9397
// TODO: Future
9498
public func stop(_ system: ActorSystem) -> Result<Void, Error> {
95-
for (_, singleton) in self.singletons {
96-
singleton.stop(system)
99+
self.singletonsLock.withLock {
100+
for (_, singleton) in self.singletons {
101+
singleton.stop(system)
102+
}
97103
}
98104
return .success(())
99105
}

Sources/DistributedActors/ActorSystem.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ public final class ActorSystem {
5050

5151
internal let _root: _ReceivesSystemMessages
5252

53-
private let terminationLock = Lock()
54-
5553
/// Allows inspecting settings that were used to configure this actor system.
5654
/// Settings are immutable and may not be changed once the system is running.
5755
public let settings: ActorSystemSettings

0 commit comments

Comments
 (0)