func handleError()

in Sources/DistributedActors/Supervision.swift [500:550]


    func handleError(context: _ActorContext<Message>, target: _Behavior<Message>, processingAction: ProcessingAction<Message>, error: Error) throws -> _Behavior<Message> {
        var errorToHandle = error
        // The following restart loop exists to support interpreting `_PreRestart` and `Start` signal interpretation failures;
        // If the actor fails during restarting, this failure becomes the new failure reason, and we supervise this failure
        // this allows "try again a few times restarts" to happen even if the fault occurs in starting the actor (e.g. opening a file or obtaining some resource failing).
        //
        // This "restart loop" matters only for:
        // - `.restartImmediately` decisions which result in throwing during `_restartPrepare` OR `_restartComplete`,
        // - or `.restartDelayed` decisions which result in throwing during `_restartPrepare`.
        //
        // Since this is a special situation somewhat, in which the tight crash loop could consume considerable resources (and maybe never recover),
        // we limit the number of times the restart is attempted

        repeat {
            switch processingAction {
            case .closure(let closure):
                context.log.warning("Actor has THROWN [\(errorToHandle)]:\(type(of: errorToHandle)) while interpreting [closure defined at \(closure.file):\(closure.line)], handling with \(self.descriptionForLogs)")
            default:
                context.log.warning("Actor has THROWN [\(errorToHandle)]:\(type(of: errorToHandle)) while interpreting \(processingAction), handling with \(self.descriptionForLogs)")
            }

            let directive: Directive
            do {
                directive = try self.handleFailure(context, target: target, failure: .error(errorToHandle), processingType: processingAction.type)
            } catch {
                // An error was thrown by our Supervisor logic while handling the failure, this is a bug and thus we crash hard
                throw _Supervision.SupervisionError.illegalDecision("Illegal supervision decision detected.", handledError: errorToHandle, error: error)
            }

            do {
                switch directive {
                case .stop:
                    return .stop(reason: .failure(.error(error)))

                case .escalate(let failure):
                    return context._downcastUnsafe._escalate(failure: failure)

                case .restartImmediately(let replacement):
                    try context._downcastUnsafe._restartPrepare()
                    return try context._downcastUnsafe._restartComplete(with: replacement)

                case .restartDelayed(let delay, let replacement):
                    try context._downcastUnsafe._restartPrepare()
                    return SupervisionRestartDelayedBehavior.after(delay: delay, with: replacement)
                }
            } catch {
                errorToHandle = error // the error captured from restarting is now the reason why we are failing, and should be passed to the supervisor
                continue // by now supervising the errorToHandle which has just occurred
            }
        } while true // the only way to break out of here is succeeding to interpret `directive` OR supervisor giving up (e.g. max nr of restarts being exhausted)
    }