in Sources/DistributedActors/Cluster/ClusterShell.swift [889:948]
func onOutboundConnectionError(_ context: _ActorContext<Message>, _ state: ClusterShellState, with remoteNode: Node, error: Error) -> _Behavior<Message> {
var state = state
state.log.debug("Failed to establish outbound channel to \(remoteNode), error: \(error)", metadata: [
"handshake/remoteNode": "\(remoteNode)",
"handshake/error": "\(error)",
])
guard let handshakeState = state.handshakeInProgress(with: remoteNode) else {
state.log.warning("Connection error for handshake which is not in progress, this should not happen, but is harmless.", metadata: [
"handshake/remoteNode": "\(remoteNode)",
"handshake/error": "\(error)",
])
return .same
}
switch handshakeState {
case .initiated(var initiated):
guard initiated.channel == nil else {
fatalError("Seems we DO have a channel already! \(initiated)\n \(state)")
}
switch initiated.onConnectionError(error) {
case .scheduleRetryHandshake(let retryDelay):
state.log.debug("Schedule handshake retry", metadata: [
"handshake/remoteNote": "\(initiated.remoteNode)",
"handshake/retryDelay": "\(retryDelay)",
])
context.timers.startSingle(
key: TimerKey("handshake-timer-\(remoteNode)"),
message: .command(.retryHandshake(initiated)),
delay: retryDelay
)
// ensure we store the updated state; since retry attempts modify the backoff state
state._handshakes[remoteNode] = .initiated(initiated)
case .giveUpOnHandshake:
if let hsmState = state.closeOutboundHandshakeChannel(with: remoteNode) {
state.log.warning("Giving up on handshake with node [\(remoteNode)]", metadata: [
"handshake/error": "\(error)",
"handshake/state": "\(hsmState)",
])
}
}
case .wasOfferedHandshake(let state):
preconditionFailure("Outbound connection error should never happen on receiving end. State was: [\(state)], error was: \(error)")
case .completed(let completedState):
// this could mean that another (perhaps inbound, rather than the outbound handshake we're attempting here) actually succeeded
state.log.notice("Stored handshake state is .completed, while outbound connection establishment failed. Assuming existing completed association is correct.", metadata: [
"handshake/error": "\(error)",
"handshake/state": "\(state)",
"handshake/completed": "\(completedState)",
])
case .inFlight:
preconditionFailure("An in-flight marker state should never be stored, yet was encountered in \(#function). State was: [\(state)], error was: \(error)")
}
return self.ready(state: state)
}