gpt4 book ai didi

ios - Swift 仅针对某些错误类型组合重试

转载 作者:行者123 更新时间:2023-12-03 23:59:06 26 4
gpt4 key购买 nike

我有一个自定义管道,我想对一些可恢复的错误代码进行 3 次重试,另外我想为可恢复错误添加一些短延迟。任何人都知道我该怎么做?

func createRequest(for message: Message) -> AnyPublisher<ResponseMessage, Error> {
Future<ResponseMessage, Error> { promise in
.....
}
.tryCatch({ error -> AnyPublisher<ResponseMessage, Error> in
// If error is a recoverable error retry, otherwise fail directly
if case let MessageBusError.messageError(responseError) = error {
if responseError.isRecoverable {
// Make a next attempt only for recoverable error
throw error
}
}
//Should fail directly if the error code is not recoverable
return Fail<ResponseMessage, Error>(error: error)
.eraseToAnyPublisher()

})
.retry(3)
.eraseToAnyPublisher()
}

最佳答案

基本上,您需要一个 retryIf运算符,因此您可以提供一个闭包来告诉Combine 哪些错误应该重试,哪些不应该重试。我不知道有这样的操作符,但为自己构建一个并不难。
惯用的方式是扩展 Publishers命名空间为您的运算符添加一个新类型,然后扩展 Publisher添加对该运算符的支持,以便您可以将它与其他运算符链接起来。
实现可能如下所示:

extension Publishers {
struct RetryIf<P: Publisher>: Publisher {
typealias Output = P.Output
typealias Failure = P.Failure

let publisher: P
let times: Int
let condition: (P.Failure) -> Bool

func receive<S>(subscriber: S) where S : Subscriber, Failure == S.Failure, Output == S.Input {
guard times > 0 else { return publisher.receive(subscriber: subscriber) }

publisher.catch { (error: P.Failure) -> AnyPublisher<Output, Failure> in
if condition(error) {
return RetryIf(publisher: publisher, times: times - 1, condition: condition).eraseToAnyPublisher()
} else {
return Fail(error: error).eraseToAnyPublisher()
}
}.receive(subscriber: subscriber)
}
}
}

extension Publisher {
func retry(times: Int, if condition: @escaping (Failure) -> Bool) -> Publishers.RetryIf<Self> {
Publishers.RetryIf(publisher: self, times: times, condition: condition)
}
}
用法:
func createRequest(for message: Message) -> AnyPublisher<ResponseMessage, Error> {
Deferred {
Future<ResponseMessage, Error> { promise in
// future code
}
}
.retry(times: 3) { error in
if case let MessageBusError.messageError(responseError) = error, responseError.isRecoverable {
return true
}
return false
}
.eraseToAnyPublisher()
}
请注意,我包裹了您的 FutureDeferred一,否则 retry运算符将毫无意义,因为闭包不会被多次执行。有关该行为的更多详细信息,请访问: Swift. Combine. Is there any way to call a publisher block more than once when retry? .

或者,您可以写 Publisher像这样的扩展:
extension Publisher {
func retry(_ times: Int, if condition: @escaping (Failure) -> Bool) -> Publishers.RetryIf<Self> {
Publishers.RetryIf(publisher: self, times: times, condition: condition)
}

func retry(_ times: Int, unless condition: @escaping (Failure) -> Bool) -> Publishers.RetryIf<Self> {
retry(times, if: { !condition($0) })
}
}
,它启用了一些时髦的东西,如下所示:
extension Error {
var isRecoverable: Bool { ... }
var isUnrecoverable: Bool { ... }
}

// retry at most 3 times while receiving recoverable errors
// bail out the first time when encountering an error that is
// not recoverable
somePublisher
.retry(3, if: \.isRecoverable)

// retry at most 3 times, bail out the first time when
// an unrecoverable the error is encountered
somePublisher
.retry(3, unless: \.isUnrecoverable)
甚至更时髦的 ruby 风格:
extension Int {
var times: Int { self }
}

somePublisher
.retry(3.times, unless: \.isUnrecoverable)

关于ios - Swift 仅针对某些错误类型组合重试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64938442/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com