Skip to content

Commit 17201e1

Browse files
committed
throw more specific error when remoteCall completion fails on shut down system
1 parent 6f44f68 commit 17201e1

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

Sources/DistributedActors/ClusterSystem.swift

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,7 @@ extension ClusterSystem {
987987
let recipient = _RemoteClusterActorPersonality<InvocationMessage>(shell: clusterShell, id: actor.id._asRemote, system: self)
988988
let arguments = invocation.arguments
989989

990-
let reply: RemoteCallReply<Res> = try await self.withCallID { callID in
990+
let reply: RemoteCallReply<Res> = try await self.withCallID(on: actor.id, target: target) { callID in
991991
let invocation = InvocationMessage(
992992
callID: callID,
993993
targetIdentifier: target.identifier,
@@ -1022,7 +1022,7 @@ extension ClusterSystem {
10221022
let recipient = _RemoteClusterActorPersonality<InvocationMessage>(shell: clusterShell, id: actor.id._asRemote, system: self)
10231023
let arguments = invocation.arguments
10241024

1025-
let reply: RemoteCallReply<_Done> = try await self.withCallID { callID in
1025+
let reply: RemoteCallReply<_Done> = try await self.withCallID(on: actor.id, target: target) { callID in
10261026
let invocation = InvocationMessage(
10271027
callID: callID,
10281028
targetIdentifier: target.identifier,
@@ -1037,22 +1037,44 @@ extension ClusterSystem {
10371037
}
10381038

10391039
private func withCallID<Reply>(
1040+
on actorID: ActorID,
1041+
target: RemoteCallTarget,
10401042
body: (CallID) -> Void
10411043
) async throws -> Reply
10421044
where Reply: AnyRemoteCallReply
10431045
{
10441046
let callID = UUID()
10451047

10461048
let timeout = RemoteCall.timeout ?? self.settings.defaultRemoteCallTimeout
1047-
let timeoutTask: Task<Void, Error> = Task {
1049+
let timeoutTask: Task<Void, Error> = Task.detached {
10481050
await Task.sleep(UInt64(timeout.nanoseconds))
10491051
guard !Task.isCancelled else {
10501052
return
10511053
}
1054+
10521055
self.inFlightCallLock.withLockVoid {
1053-
if let continuation = self._inFlightCalls.removeValue(forKey: callID) {
1054-
continuation.resume(throwing: RemoteCallError.timedOut(TimeoutError(message: "Remote call timed out", timeout: timeout)))
1056+
guard let continuation = self._inFlightCalls.removeValue(forKey: callID) else {
1057+
// remoteCall was already completed successfully, nothing to do here
1058+
return
10551059
}
1060+
1061+
let error: Error
1062+
if self.isShuttingDown {
1063+
// If the system is shutting down, we should offer a more specific error;
1064+
//
1065+
// We may not be getting responses simply because we've shut down associations
1066+
// and cannot receive them anymore.
1067+
// Some subsystems may ignore those errors, since they are "expected".
1068+
//
1069+
// If we're shutting down, it is okay to not get acknowledgements to calls for example,
1070+
// and we don't care about them missing -- we're shutting down anyway.
1071+
error = RemoteCallError.clusterAlreadyShutDown
1072+
} else {
1073+
error = RemoteCallError.timedOut(
1074+
TimeoutError(message: "Remote call [\(callID)] to [\(target)](\(actorID)) timed out", timeout: timeout))
1075+
}
1076+
1077+
continuation.resume(throwing: error)
10561078
}
10571079
}
10581080
defer {

0 commit comments

Comments
 (0)