diff --git a/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo/main.swift b/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo/main.swift index 1f740965e..f91ed98e0 100644 --- a/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo/main.swift +++ b/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo/main.swift @@ -47,4 +47,4 @@ case let unknown: exit(-1) } -system.park() +try! system.park() diff --git a/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo_service/main.swift b/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo_service/main.swift index 86b95532b..3e034ad5c 100644 --- a/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo_service/main.swift +++ b/IntegrationTests/disabled_tests_03_xpc_actorable/it_XPCActorable_echo_service/main.swift @@ -36,5 +36,5 @@ try! _file.append("service booted...\n") let service = try XPCActorableService(system, XPCEchoService.init) service.park() -system.park() // TODO: system park should invoke the service park, we only need to park once for XPC to kickoff dispatch_main +try! system.park() // TODO: system park should invoke the service park, we only need to park once for XPC to kickoff dispatch_main // unreachable, park never exits diff --git a/Samples/Sources/SampleCRDTPlayground/CRDTPlayground.swift b/Samples/Sources/SampleCRDTPlayground/CRDTPlayground.swift index 63aa8ed65..505a289b9 100644 --- a/Samples/Sources/SampleCRDTPlayground/CRDTPlayground.swift +++ b/Samples/Sources/SampleCRDTPlayground/CRDTPlayground.swift @@ -67,7 +67,7 @@ struct CRDTPlayground { peer.tell("write-2-\(peer.path.name)") } - first.park(atMost: time) + try! first.park(atMost: time) } } diff --git a/Samples/Sources/SampleCluster/main.swift b/Samples/Sources/SampleCluster/main.swift index 8343914a8..f70ec3e74 100644 --- a/Samples/Sources/SampleCluster/main.swift +++ b/Samples/Sources/SampleCluster/main.swift @@ -76,6 +76,7 @@ system.cluster.events.subscribe(eventsListener) // <2> // case announcement(String) // case text(String, from: ActorRef) // } + // tag::cluster-sample-actors-discover-and-chat[] let chatter: ActorRef = try system.spawn( "chatter", @@ -87,7 +88,7 @@ let chatter: ActorRef = try system.spawn( system.receptionist.register(chatter, with: "chat-room") // <1> if system.cluster.uniqueNode.port == 7337 { // <2> - let greeter = try system.spawn( + try system.spawn( "greeter", of: Reception.Listing>.self, .setup { context in // <3> @@ -105,4 +106,4 @@ if system.cluster.uniqueNode.port == 7337 { // <2> // end::cluster-sample-actors-discover-and-chat[] -system.park(atMost: .seconds(6000)) +try! system.park(atMost: .seconds(6000)) diff --git a/Samples/Sources/SampleDiningPhilosophers/DiningPhilosophers.swift b/Samples/Sources/SampleDiningPhilosophers/DiningPhilosophers.swift index c3efd274a..51be01f28 100644 --- a/Samples/Sources/SampleDiningPhilosophers/DiningPhilosophers.swift +++ b/Samples/Sources/SampleDiningPhilosophers/DiningPhilosophers.swift @@ -32,6 +32,6 @@ struct DiningPhilosophers { let _: Philosopher.Ref = try system.spawn("Cory", Philosopher(left: fork3, right: fork4).behavior) let _: Philosopher.Ref = try system.spawn("Norman", Philosopher(left: fork4, right: fork5).behavior) - system.park(atMost: time) + try system.park(atMost: time) } } diff --git a/Samples/Sources/SampleDiningPhilosophers/DistributedDiningPhilosophers.swift b/Samples/Sources/SampleDiningPhilosophers/DistributedDiningPhilosophers.swift index 84e8b6363..5a93c64b6 100644 --- a/Samples/Sources/SampleDiningPhilosophers/DistributedDiningPhilosophers.swift +++ b/Samples/Sources/SampleDiningPhilosophers/DistributedDiningPhilosophers.swift @@ -54,6 +54,6 @@ struct DistributedDiningPhilosophers { _ = try systemC.spawn("Cory", Philosopher(left: fork3, right: fork4).behavior) _ = try systemC.spawn("Norman", Philosopher(left: fork4, right: fork5).behavior) - systemA.park(atMost: time) + try systemA.park(atMost: time) } } diff --git a/Samples/Sources/SampleDistributedCRDTScoreGame/ScoreGame.swift b/Samples/Sources/SampleDistributedCRDTScoreGame/ScoreGame.swift index 1d3787deb..ef01f978b 100644 --- a/Samples/Sources/SampleDistributedCRDTScoreGame/ScoreGame.swift +++ b/Samples/Sources/SampleDistributedCRDTScoreGame/ScoreGame.swift @@ -62,7 +62,7 @@ struct ScoreGame { // which other non participants may observe as well. _ = try first.spawn("game-engine", self.game(with: players)) - first.park(atMost: time) + try first.park(atMost: time) } } diff --git a/Samples/Sources/SampleGenActorsDiningPhilosophers/DistributedDiningPhilosophers.swift b/Samples/Sources/SampleGenActorsDiningPhilosophers/DistributedDiningPhilosophers.swift index 015f2326a..5cb020d46 100644 --- a/Samples/Sources/SampleGenActorsDiningPhilosophers/DistributedDiningPhilosophers.swift +++ b/Samples/Sources/SampleGenActorsDiningPhilosophers/DistributedDiningPhilosophers.swift @@ -54,6 +54,6 @@ struct DistributedDiningPhilosophers { _ = try systemC.spawn("Cory") { Philosopher(context: $0, leftFork: fork3, rightFork: fork4) } _ = try systemC.spawn("Norman") { Philosopher(context: $0, leftFork: fork4, rightFork: fork5) } - systemA.park(atMost: time) + try systemA.park(atMost: time) } } diff --git a/Samples/Sources/SampleMetrics/main.swift b/Samples/Sources/SampleMetrics/main.swift index b7611b62a..67a3c3ad8 100644 --- a/Samples/Sources/SampleMetrics/main.swift +++ b/Samples/Sources/SampleMetrics/main.swift @@ -104,5 +104,5 @@ for i in 1 ... 10 { Thread.sleep(.seconds(100)) -system.shutdown().wait() +try! system.shutdown().wait() print("~~~~~~~~~~~~~~~ SHUTTING DOWN ~~~~~~~~~~~~~~~") diff --git a/Samples/Sources/XPCActorCaller/main.swift b/Samples/Sources/XPCActorCaller/main.swift index 1b77b72a9..38a76a29a 100644 --- a/Samples/Sources/XPCActorCaller/main.swift +++ b/Samples/Sources/XPCActorCaller/main.swift @@ -41,7 +41,7 @@ reply.withTimeout(after: .seconds(3))._onComplete { system.log.info("Reply from service.greet(Capybara) = \($0)") } -system.park() +try! system.park() // end::xpc_example[] #endif diff --git a/Sources/DistributedActors/ActorSystem.swift b/Sources/DistributedActors/ActorSystem.swift index cc6e24903..3df142322 100644 --- a/Sources/DistributedActors/ActorSystem.swift +++ b/Sources/DistributedActors/ActorSystem.swift @@ -118,7 +118,7 @@ public final class ActorSystem { // ==== ---------------------------------------------------------------------------------------------------------------- // MARK: Shutdown - private var shutdownReceptacle = BlockingReceptacle() + private var shutdownReceptacle = BlockingReceptacle() private let shutdownLock = Lock() /// Greater than 0 shutdown has been initiated / is in progress. @@ -322,7 +322,7 @@ public final class ActorSystem { /// This call is also offered to underlying transports which may have to perform the blocking wait themselves /// (most notably, `ProcessIsolated` does so). Please refer to your configured transports documentation, /// to learn about exact semantics of parking a system while using them. - public func park(atMost parkTimeout: TimeAmount? = nil) { + public func park(atMost parkTimeout: TimeAmount? = nil) throws { let howLongParkingMsg = parkTimeout == nil ? "indefinitely" : "for \(parkTimeout!.prettyDescription)" self.log.info("Parking actor system \(howLongParkingMsg)...") @@ -332,9 +332,13 @@ public final class ActorSystem { } if let maxParkingTime = parkTimeout { - self.shutdownReceptacle.wait(atMost: maxParkingTime) + if let error = self.shutdownReceptacle.wait(atMost: maxParkingTime).flatMap({ $0 }) { + throw error + } } else { - self.shutdownReceptacle.wait() + if let error = self.shutdownReceptacle.wait() { + throw error + } } } @@ -345,29 +349,38 @@ public final class ActorSystem { #endif public struct Shutdown { - private let receptacle: BlockingReceptacle + private let receptacle: BlockingReceptacle - init(receptacle: BlockingReceptacle) { + init(receptacle: BlockingReceptacle) { self.receptacle = receptacle } public func wait(atMost timeout: TimeAmount) throws { - guard self.receptacle.wait(atMost: timeout) != nil else { - throw TimeoutError(message: "Shutdown did not complete", timeout: timeout) + if let error = self.receptacle.wait(atMost: timeout).flatMap({ $0 }) { + throw error } } - public func wait() { - self.receptacle.wait() + public func wait() throws { + if let error = self.receptacle.wait() { + throw error + } } } - /// Forcefully stops this actor system and all actors that live within. This is an asynchronous operation - /// and will be executed on a separate thread. + /// Forcefully stops this actor system and all actors that live within it. + /// This is an asynchronous operation and will be executed on a separate thread. /// + /// You can use `shutdown().wait()` to synchronously await on the system's termination, + /// or provide a callback to be executed after the system has completed it's shutdown. + /// + /// - Parameters: + /// - queue: allows configuring on which dispatch queue the shutdown operation will be finalized. + /// - afterShutdownCompleted: optional callback to be invoked when the system has completed shutting down. + /// Will be invoked on the passed in `queue` (which defaults to `DispatchQueue.global()`). /// - Returns: A `Shutdown` value that can be waited upon until the system has completed the shutdown. @discardableResult - public func shutdown() -> Shutdown { + public func shutdown(queue: DispatchQueue = DispatchQueue.global(), afterShutdownCompleted: @escaping (Error?) -> Void = { _ in () }) -> Shutdown { guard self.shutdownFlag.add(1) == 0 else { // shutdown already kicked off by someone else return Shutdown(receptacle: self.shutdownReceptacle) @@ -375,19 +388,24 @@ public final class ActorSystem { self.settings.plugins.stopAll(self) - DispatchQueue.global().async { + queue.async { self.log.log(level: .debug, "Shutting down actor system [\(self.name)]. All actors will be stopped.", file: #file, function: #function, line: #line) if let cluster = self._cluster { let receptacle = BlockingReceptacle() - cluster.ref.tell(.command(.shutdown(receptacle))) // FIXME: should be shutdown - receptacle.wait(atMost: .milliseconds(300)) // FIXME: configure + cluster.ref.tell(.command(.shutdown(receptacle))) + receptacle.wait() } self.userProvider.stopAll() self.systemProvider.stopAll() self.dispatcher.shutdown() - try! self._eventLoopGroup.syncShutdownGracefully() - self._receptionistRef = self.deadLetters.adapted() + do { + try self._eventLoopGroup.syncShutdownGracefully() + self._receptionistRef = self.deadLetters.adapted() + } catch { + self.shutdownReceptacle.offerOnce(error) + afterShutdownCompleted(error) + } /// Only once we've shutdown all dispatchers and loops, we clear cycles between the serialization and system, /// as they should never be invoked anymore. @@ -396,7 +414,8 @@ public final class ActorSystem { self._cluster = nil } - self.shutdownReceptacle.offerOnce(()) + self.shutdownReceptacle.offerOnce(nil) + afterShutdownCompleted(nil) } return Shutdown(receptacle: self.shutdownReceptacle) diff --git a/Sources/DistributedActors/Refs.swift b/Sources/DistributedActors/Refs.swift index f61c9b5d1..32bae0a9d 100644 --- a/Sources/DistributedActors/Refs.swift +++ b/Sources/DistributedActors/Refs.swift @@ -585,7 +585,7 @@ public class Guardian { system.log.error("\(message)", metadata: ["actor/path": "\(self.address.path)"]) _ = try! Thread { - system.shutdown().wait() // so we don't block anyone who sent us this signal (as we execute synchronously in the guardian) + try! system.shutdown().wait() // so we don't block anyone who sent us this signal (as we execute synchronously in the guardian) print("Guardian shutdown of [\(system.name)] ActorSystem complete.") } #if os(iOS) || os(watchOS) || os(tvOS) diff --git a/Sources/DistributedActorsBenchmarks/ActorMessageFloodingBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorMessageFloodingBenchmarks.swift index a860d6203..acfc7b3dc 100644 --- a/Sources/DistributedActorsBenchmarks/ActorMessageFloodingBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorMessageFloodingBenchmarks.swift @@ -38,7 +38,7 @@ private func setUp() { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } diff --git a/Sources/DistributedActorsBenchmarks/ActorPingPongBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorPingPongBenchmarks.swift index 2de916b5a..b46616a41 100644 --- a/Sources/DistributedActorsBenchmarks/ActorPingPongBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorPingPongBenchmarks.swift @@ -93,7 +93,7 @@ private func setUp(and postSetUp: () -> Void = { () in () }) { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } @@ -255,6 +255,6 @@ private func bench_actors_ping_pong(numActors: Int) -> (Int) -> Void { let time = SwiftBenchmarkTools.Timer().getTimeAsInt() - startNanoTime pprint(" \(totalNumMessages) messages by \(numActors) actors took: \(time.milliseconds) ms (total: \(totalNumMessages / time.milliseconds * 1000) msg/s)") - system.shutdown().wait() + try! system.shutdown().wait() } } diff --git a/Sources/DistributedActorsBenchmarks/ActorRemotePingPongBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorRemotePingPongBenchmarks.swift index 40ad95e69..603cd1c2a 100644 --- a/Sources/DistributedActorsBenchmarks/ActorRemotePingPongBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorRemotePingPongBenchmarks.swift @@ -80,9 +80,9 @@ private func setUp(and postSetUp: () -> Void = { () in () }) { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil - _pongNode?.shutdown().wait() + try! _pongNode?.shutdown().wait() _pongNode = nil } @@ -243,6 +243,6 @@ private func bench_actors_remote_ping_pong(numActors: Int) -> (Int) -> Void { let time = SwiftBenchmarkTools.Timer().getTimeAsInt() - startNanoTime pprint(" \(totalNumMessages) messages by \(numActors) actors took: \(time.milliseconds) ms (total: \(totalNumMessages / time.milliseconds * 1000) msg/s)") - system.shutdown().wait() + try! system.shutdown().wait() } } diff --git a/Sources/DistributedActorsBenchmarks/ActorResolveBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorResolveBenchmarks.swift index 40783243f..f1b8573f7 100644 --- a/Sources/DistributedActorsBenchmarks/ActorResolveBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorResolveBenchmarks.swift @@ -38,7 +38,7 @@ private func setUp(and postSetUp: () -> Void) { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } diff --git a/Sources/DistributedActorsBenchmarks/ActorRingBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorRingBenchmarks.swift index 8080ef0f3..3b732ed24 100644 --- a/Sources/DistributedActorsBenchmarks/ActorRingBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorRingBenchmarks.swift @@ -55,7 +55,7 @@ private func setUp(and postSetUp: () -> Void = { () in () }) { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } diff --git a/Sources/DistributedActorsBenchmarks/ActorSpawnBenchmarks.swift b/Sources/DistributedActorsBenchmarks/ActorSpawnBenchmarks.swift index 72139f407..9f0777998 100644 --- a/Sources/DistributedActorsBenchmarks/ActorSpawnBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/ActorSpawnBenchmarks.swift @@ -60,7 +60,7 @@ func bench_SpawnTopLevel(_ actorCount: Int) throws { print("Spawned \(actorCount) top-level actors in \(String(format: "%.3f", seconds)) seconds. (\(perSecond) actors/s)") let shutdownStart = timer.getTime() - system.shutdown().wait() + try! system.shutdown().wait() let shutdownStop = timer.getTime() let shutdownTime = timer.diffTimeInNanoSeconds(from: shutdownStart, to: shutdownStop) let shutdownSeconds = (Double(shutdownTime) / 1_000_000_000) @@ -99,7 +99,7 @@ func bench_SpawnChildren(_ actorCount: Int) throws { print("Spawned \(actorCount) child actors in \(String(format: "%.3f", seconds)) seconds. (\(perSecond) actors/s)") let shutdownStart = timer.getTime() - system.shutdown().wait() + try! system.shutdown().wait() let shutdownStop = timer.getTime() let shutdownTime = timer.diffTimeInNanoSeconds(from: shutdownStart, to: shutdownStop) let shutdownSeconds = (Double(shutdownTime) / 1_000_000_000) diff --git a/Sources/DistributedActorsBenchmarks/SerializationCodableBenchmarks.swift b/Sources/DistributedActorsBenchmarks/SerializationCodableBenchmarks.swift index a64b1ea94..c7e892fe8 100644 --- a/Sources/DistributedActorsBenchmarks/SerializationCodableBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/SerializationCodableBenchmarks.swift @@ -47,7 +47,7 @@ private func setUp(and postSetUp: () -> Void = { () in () }) { } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } diff --git a/Sources/DistributedActorsBenchmarks/SerializationProtobufBenchmarks.swift b/Sources/DistributedActorsBenchmarks/SerializationProtobufBenchmarks.swift index 6d008bb2b..4471e287f 100644 --- a/Sources/DistributedActorsBenchmarks/SerializationProtobufBenchmarks.swift +++ b/Sources/DistributedActorsBenchmarks/SerializationProtobufBenchmarks.swift @@ -69,7 +69,7 @@ private func setUp(and postSetUp: () -> Void = { () in } private func tearDown() { - system.shutdown().wait() + try! system.shutdown().wait() _system = nil } diff --git a/Sources/DistributedActorsTestKit/Cluster/ClusteredActorSystemsXCTestCase.swift b/Sources/DistributedActorsTestKit/Cluster/ClusteredActorSystemsXCTestCase.swift index ef85566dc..df74b4e26 100644 --- a/Sources/DistributedActorsTestKit/Cluster/ClusteredActorSystemsXCTestCase.swift +++ b/Sources/DistributedActorsTestKit/Cluster/ClusteredActorSystemsXCTestCase.swift @@ -104,7 +104,7 @@ open class ClusteredActorSystemsXCTestCase: XCTestCase { self.printAllCapturedLogs() } - self._nodes.forEach { $0.shutdown().wait() } + self._nodes.forEach { try! $0.shutdown().wait() } self._nodes = [] self._testKits = [] diff --git a/Tests/ActorSingletonPluginTests/ActorSingletonPluginTests.swift b/Tests/ActorSingletonPluginTests/ActorSingletonPluginTests.swift index 28a5b85d4..123f4b3bc 100644 --- a/Tests/ActorSingletonPluginTests/ActorSingletonPluginTests.swift +++ b/Tests/ActorSingletonPluginTests/ActorSingletonPluginTests.swift @@ -26,7 +26,7 @@ final class ActorSingletonPluginTests: ActorSystemXCTestCase { } defer { - system.shutdown().wait() + try! system.shutdown().wait() } let replyProbe = ActorTestKit(system).spawnTestProbe(expecting: String.self) @@ -50,7 +50,7 @@ final class ActorSingletonPluginTests: ActorSystemXCTestCase { } defer { - system.shutdown().wait() + try! system.shutdown().wait() } let replyProbe = ActorTestKit(system).spawnTestProbe(expecting: String.self) diff --git a/Tests/DistributedActorsDocumentationTests/Actorable/ActorableActorTestKitDocExamples.swift b/Tests/DistributedActorsDocumentationTests/Actorable/ActorableActorTestKitDocExamples.swift index 42962505e..41facf39d 100644 --- a/Tests/DistributedActorsDocumentationTests/Actorable/ActorableActorTestKitDocExamples.swift +++ b/Tests/DistributedActorsDocumentationTests/Actorable/ActorableActorTestKitDocExamples.swift @@ -44,7 +44,7 @@ final class ActorTestKitTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() } // tag::test[] diff --git a/Tests/DistributedActorsDocumentationTests/ClusteringDocExamples.swift b/Tests/DistributedActorsDocumentationTests/ClusteringDocExamples.swift index c2a1ab1e8..b9469ef97 100644 --- a/Tests/DistributedActorsDocumentationTests/ClusteringDocExamples.swift +++ b/Tests/DistributedActorsDocumentationTests/ClusteringDocExamples.swift @@ -31,7 +31,7 @@ class ClusteringDocExamples: XCTestCase { } // end::config_tls[] - system.shutdown().wait() + try! system.shutdown().wait() } func example_config_tls_passphrase() throws { @@ -44,6 +44,6 @@ class ClusteringDocExamples: XCTestCase { } // end::config_tls_passphrase[] - system.shutdown().wait() + try! system.shutdown().wait() } } diff --git a/Tests/DistributedActorsDocumentationTests/InteropDocExamples.swift b/Tests/DistributedActorsDocumentationTests/InteropDocExamples.swift index 69ee59881..28a486d5d 100644 --- a/Tests/DistributedActorsDocumentationTests/InteropDocExamples.swift +++ b/Tests/DistributedActorsDocumentationTests/InteropDocExamples.swift @@ -27,7 +27,7 @@ class InteropDocExamples: XCTestCase { // end::message_greetings[] let system = ActorSystem("System") - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } let behavior: Behavior = .receiveMessage { _ in // ... .same @@ -58,7 +58,7 @@ class InteropDocExamples: XCTestCase { // end::asyncOp_sendResult_insideActor_enum_Messages[] let system = ActorSystem("System") - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } func someComputation() -> String { "test" @@ -116,7 +116,7 @@ class InteropDocExamples: XCTestCase { // end::asyncOp_onResultAsync_enum_Messages[] let system = ActorSystem("System") - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let eventLoop = eventLoopGroup.next() func fetchUser(_: String) -> EventLoopFuture { @@ -167,7 +167,7 @@ class InteropDocExamples: XCTestCase { // end::asyncOp_awaitResult_enum_Messages[] let system = ActorSystem("System") - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let eventLoop = eventLoopGroup.next() func fetchDataAsync() -> EventLoopFuture { @@ -206,7 +206,7 @@ class InteropDocExamples: XCTestCase { } let system = ActorSystem("System") - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) let eventLoop = eventLoopGroup.next() func fetchDataAsync() -> EventLoopFuture { diff --git a/Tests/DistributedActorsTestKitTests/ActorTestKitTests.swift b/Tests/DistributedActorsTestKitTests/ActorTestKitTests.swift index a2ea6b578..fdab49244 100644 --- a/Tests/DistributedActorsTestKitTests/ActorTestKitTests.swift +++ b/Tests/DistributedActorsTestKitTests/ActorTestKitTests.swift @@ -26,7 +26,7 @@ final class ActorTestKitTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() } func test_error_withMessage() throws { diff --git a/Tests/DistributedActorsTestKitTests/ActorTestProbeTests.swift b/Tests/DistributedActorsTestKitTests/ActorTestProbeTests.swift index 2b40cf739..17abc6293 100644 --- a/Tests/DistributedActorsTestKitTests/ActorTestProbeTests.swift +++ b/Tests/DistributedActorsTestKitTests/ActorTestProbeTests.swift @@ -26,7 +26,7 @@ class ActorTestProbeTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() } func test_maybeExpectMessage_shouldReturnTheReceivedMessage() throws { diff --git a/Tests/DistributedActorsTests/ActorAskTests.swift b/Tests/DistributedActorsTests/ActorAskTests.swift index fa33dbe21..8127e8560 100644 --- a/Tests/DistributedActorsTests/ActorAskTests.swift +++ b/Tests/DistributedActorsTests/ActorAskTests.swift @@ -214,7 +214,7 @@ final class ActorAskTests: ActorSystemXCTestCase { } ) - system.shutdown().wait() + try! system.shutdown().wait() _ = ref.ask(for: String.self, timeout: .milliseconds(300)) { replyTo in TestMessage(replyTo: replyTo) diff --git a/Tests/DistributedActorsTests/ActorLeakingTests.swift b/Tests/DistributedActorsTests/ActorLeakingTests.swift index 93f146521..aa82976e0 100644 --- a/Tests/DistributedActorsTests/ActorLeakingTests.swift +++ b/Tests/DistributedActorsTests/ActorLeakingTests.swift @@ -234,7 +234,7 @@ final class ActorLeakingTests: ActorSystemXCTestCase { for n in 1 ... 5 { let system = ActorSystem("Test-\(n)") - system.shutdown().wait() + try! system.shutdown().wait() } ActorSystem.actorSystemInitCounter.load().shouldEqual(initialSystemCount) @@ -284,7 +284,7 @@ final class ActorLeakingTests: ActorSystemXCTestCase { context.log.trace("Not going to be logged") return .receiveMessage { _ in .same } }) - system?.shutdown().wait() + try! system?.shutdown().wait() system = nil ActorSystem.actorSystemInitCounter.load().shouldEqual(initialSystemCount) @@ -304,7 +304,7 @@ final class ActorLeakingTests: ActorSystemXCTestCase { context.log.warning("Not going to be logged") return .receiveMessage { _ in .same } }) - system?.shutdown().wait() + try! system?.shutdown().wait() system = nil ActorSystem.actorSystemInitCounter.load().shouldEqual(initialSystemCount) diff --git a/Tests/DistributedActorsTests/ActorRefAdapterTests.swift b/Tests/DistributedActorsTests/ActorRefAdapterTests.swift index 28733227d..5384bc2dc 100644 --- a/Tests/DistributedActorsTests/ActorRefAdapterTests.swift +++ b/Tests/DistributedActorsTests/ActorRefAdapterTests.swift @@ -237,7 +237,7 @@ class ActorRefAdapterTests: ActorSystemXCTestCase { let system = ActorSystem("\(type(of: self))-2") { settings in settings.logging.logger = logCapture.logger(label: settings.cluster.node.systemName) } - defer { system.shutdown().wait() } + defer { try! system.shutdown().wait() } let probe = self.testKit.spawnTestProbe(expecting: String.self) let receiveRefProbe = self.testKit.spawnTestProbe(expecting: ActorRef.self) diff --git a/Tests/DistributedActorsTests/ActorSystemTests.swift b/Tests/DistributedActorsTests/ActorSystemTests.swift index dc6dcefab..279a54e3a 100644 --- a/Tests/DistributedActorsTests/ActorSystemTests.swift +++ b/Tests/DistributedActorsTests/ActorSystemTests.swift @@ -65,7 +65,7 @@ final class ActorSystemTests: ActorSystemXCTestCase { p.watch(ref1) p.watch(ref2) - system2.shutdown().wait() + try system2.shutdown().wait() try p.expectTerminatedInAnyOrder([ref1.asAddressable, ref2.asAddressable]) @@ -104,7 +104,7 @@ final class ActorSystemTests: ActorSystemXCTestCase { p.watch(selfSender) - system2.shutdown().wait() + try system2.shutdown().wait() try p.expectTerminated(selfSender) } @@ -118,4 +118,15 @@ final class ActorSystemTests: ActorSystemXCTestCase { ref.address.path.shouldEqual(ActorPath._dead.appending(segments: path.segments)) ref.address.incarnation.shouldEqual(address.incarnation) } + + func test_shutdown_callbackShouldBeInvoked() throws { + let system = ActorSystem("ShutMeDown") + let receptacle = BlockingReceptacle() + + system.shutdown(afterShutdownCompleted: { error in + receptacle.offerOnce(error) + }) + + receptacle.wait(atMost: .seconds(3))!.shouldBeNil() + } } diff --git a/Tests/DistributedActorsTests/BehaviorTests.swift b/Tests/DistributedActorsTests/BehaviorTests.swift index 45db50557..e4db80404 100644 --- a/Tests/DistributedActorsTests/BehaviorTests.swift +++ b/Tests/DistributedActorsTests/BehaviorTests.swift @@ -350,7 +350,7 @@ final class BehaviorTests: ActorSystemXCTestCase { settings.logging.logger = capture.logger(label: "mock") } defer { - system.shutdown().wait() + try! system.shutdown().wait() } let p: ActorTestProbe = self.testKit.spawnTestProbe() diff --git a/Tests/DistributedActorsTests/Cluster/DowningStrategy/DowningClusteredTests.swift b/Tests/DistributedActorsTests/Cluster/DowningStrategy/DowningClusteredTests.swift index 9a9c5d48d..e2359e777 100644 --- a/Tests/DistributedActorsTests/Cluster/DowningStrategy/DowningClusteredTests.swift +++ b/Tests/DistributedActorsTests/Cluster/DowningStrategy/DowningClusteredTests.swift @@ -246,7 +246,7 @@ final class DowningClusteredTests: ClusteredActorSystemsXCTestCase { pinfo("Downing \(nodesToDown.count) nodes: \(nodesToDown.map { $0.cluster.uniqueNode })") for node in nodesToDown { - node.shutdown().wait() + try! node.shutdown().wait() } func expectedDownMemberEventsFishing( diff --git a/Tests/DistributedActorsTests/Cluster/Reception/OpLogClusterReceptionistClusteredTests.swift b/Tests/DistributedActorsTests/Cluster/Reception/OpLogClusterReceptionistClusteredTests.swift index 398c621c9..520940309 100644 --- a/Tests/DistributedActorsTests/Cluster/Reception/OpLogClusterReceptionistClusteredTests.swift +++ b/Tests/DistributedActorsTests/Cluster/Reception/OpLogClusterReceptionistClusteredTests.swift @@ -208,7 +208,7 @@ final class OpLogClusterReceptionistClusteredTests: ClusteredActorSystemsXCTestC refA.tell("stop") refB.tell("stop") case .shutdownNode: - first.shutdown().wait() + try first.shutdown().wait() } try remoteLookupProbe.eventuallyExpectListing(expected: [], within: .seconds(3)) @@ -291,7 +291,7 @@ final class OpLogClusterReceptionistClusteredTests: ClusteredActorSystemsXCTestC try p2.eventuallyExpectListing(expected: [firstRef, secondRef], within: .seconds(3)) // crash the second node - second.shutdown().wait() + try second.shutdown().wait() // it should be removed from all listings; on both nodes, for all keys try p1.eventuallyExpectListing(expected: [firstRef], within: .seconds(5)) @@ -328,7 +328,7 @@ final class OpLogClusterReceptionistClusteredTests: ClusteredActorSystemsXCTestC try p2.eventuallyExpectListing(expected: allRefs, within: .seconds(5)) // crash the second node - second.shutdown().wait() + try second.shutdown().wait() // it should be removed from all listings; on both nodes, for all keys try p1.eventuallyExpectListing(expected: [firstRef], within: .seconds(5), verbose: true) diff --git a/Tests/DistributedActorsTests/Cluster/RemoteMessagingClusteredTests.swift b/Tests/DistributedActorsTests/Cluster/RemoteMessagingClusteredTests.swift index a94d5033a..0ea8e8f41 100644 --- a/Tests/DistributedActorsTests/Cluster/RemoteMessagingClusteredTests.swift +++ b/Tests/DistributedActorsTests/Cluster/RemoteMessagingClusteredTests.swift @@ -271,7 +271,7 @@ final class RemoteMessagingClusteredTests: ClusteredActorSystemsXCTestCase { settings.serialization.register(SerializationTestMessage.self) settings.serialization.register(EchoTestMessage.self) } - defer { thirdSystem.shutdown().wait() } + defer { try! thirdSystem.shutdown().wait() } thirdSystem.cluster.join(node: local.cluster.uniqueNode.node) thirdSystem.cluster.join(node: remote.cluster.uniqueNode.node) diff --git a/Tests/DistributedActorsTests/Cluster/SystemMessageRedeliveryHandlerTests.swift b/Tests/DistributedActorsTests/Cluster/SystemMessageRedeliveryHandlerTests.swift index 767630581..4ce734f4c 100644 --- a/Tests/DistributedActorsTests/Cluster/SystemMessageRedeliveryHandlerTests.swift +++ b/Tests/DistributedActorsTests/Cluster/SystemMessageRedeliveryHandlerTests.swift @@ -162,7 +162,7 @@ final class SystemMessageRedeliveryHandlerTests: ActorSystemXCTestCase { // // let settings = OutboundSystemMessageRedeliverySettings() // let system = ActorSystem("OtherSystem") // formatting is such specific to align names in printout -// defer { system.shutdown().wait() } +// defer { try! system.shutdown().wait() } // // var lossySettings = FaultyNetworkSimulationSettings(mode: .drop(probability: 0.25)) // lossySettings.label = " (DROP) :" // formatting is such specific to align names in printout diff --git a/Tests/DistributedActorsTests/Cluster/SystemMessagesRedeliveryTests.swift b/Tests/DistributedActorsTests/Cluster/SystemMessagesRedeliveryTests.swift index cb9ff1d02..1eae17481 100644 --- a/Tests/DistributedActorsTests/Cluster/SystemMessagesRedeliveryTests.swift +++ b/Tests/DistributedActorsTests/Cluster/SystemMessagesRedeliveryTests.swift @@ -257,7 +257,7 @@ final class SystemMessagesRedeliveryTests: ActorSystemXCTestCase { func test_redelivery_systemMessage_serialization() throws { let system = ActorSystem("\(type(of: self))") defer { - system.shutdown().wait() + try! system.shutdown().wait() } func validateRoundTrip(_ value: T) throws { diff --git a/Tests/DistributedActorsTests/SerializationPoolTests.swift b/Tests/DistributedActorsTests/SerializationPoolTests.swift index 8c58fe3ff..5bd6794d4 100644 --- a/Tests/DistributedActorsTests/SerializationPoolTests.swift +++ b/Tests/DistributedActorsTests/SerializationPoolTests.swift @@ -107,7 +107,7 @@ final class SerializationPoolTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() try! self.elg.syncShutdownGracefully() } diff --git a/Tests/DistributedActorsTests/SerializationTests.swift b/Tests/DistributedActorsTests/SerializationTests.swift index b64535e9d..943c98a86 100644 --- a/Tests/DistributedActorsTests/SerializationTests.swift +++ b/Tests/DistributedActorsTests/SerializationTests.swift @@ -304,10 +304,10 @@ class SerializationTests: ActorSystemXCTestCase { echo.tell("hi!") // is a built-in serializable message try p.expectMessage("echo:hi!") } catch { - s2.shutdown().wait() + try! s2.shutdown().wait() throw error } - s2.shutdown().wait() + try! s2.shutdown().wait() } // ==== ------------------------------------------------------------------------------------------------------------ @@ -408,7 +408,7 @@ class SerializationTests: ActorSystemXCTestCase { settings.serialization.register(PListXMLCodableTest.self, serializerID: .foundationPropertyListBinary) // on purpose "wrong" format } defer { - system2.shutdown().wait() + try! system2.shutdown().wait() } _ = try shouldThrow { diff --git a/Tests/GenActorsTests/GenCodableTests.swift b/Tests/GenActorsTests/GenCodableTests.swift index c5ed42560..b6118271a 100644 --- a/Tests/GenActorsTests/GenCodableTests.swift +++ b/Tests/GenActorsTests/GenCodableTests.swift @@ -29,7 +29,7 @@ final class GenCodableTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() self.system = nil self.testKit = nil } diff --git a/Tests/GenActorsTests/GenerateActorsTests.swift b/Tests/GenActorsTests/GenerateActorsTests.swift index e70e97920..971ab3dd9 100644 --- a/Tests/GenActorsTests/GenerateActorsTests.swift +++ b/Tests/GenActorsTests/GenerateActorsTests.swift @@ -32,7 +32,7 @@ final class GenerateActorsTests: XCTestCase { } override func tearDown() { - self.system.shutdown().wait() + try! self.system.shutdown().wait() } // ==== ----------------------------------------------------------------------------------------------------------------