ios - How to retry failed web service calls with time delay in ios app
问题描述
I am developing an IOS app and as per the requirement I need to retry all failed api for 3 times with 3 seconds delay. In order to do that I have added an extension to a Publisher as follows, but there is one small problem with this code, after the last attempt if I get a failed response then it takes 3 seconds to execute the expected failure code. I need to show failure message as soon as last attempt fails, is there any way to handle this?
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self
.delayIfFailure(for: delay, scheduler: scheduler)
.retry(retries)
.eraseToAnyPublisher()
}
private func delayIfFailure<S>(
for delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> AnyPublisher<Output, Failure> where S: Scheduler {
self.catch { error in
Future { completion in
scheduler.schedule(after: scheduler.now.advanced(by: delay)) {
completion(.failure(error))
}
}
}
.eraseToAnyPublisher()
}
}
解决方案
It would probably be best to create a custom Publisher
, with the idea being that you'd keep track of the number of failures, and either return a delayed publisher (that fails) under normal conditions, or a non-delayed publisher for the last retry.
struct RetryWithDelay<Upstream: Publisher, S: Scheduler>: Publisher {
typealias Output = Upstream.Output
typealias Failure = Upstream.Failure
let upstream: Upstream
let retries: Int
let interval: S.SchedulerTimeType.Stride
let scheduler: S
func receive<Sub>(subscriber: Sub)
where Sub : Subscriber,
Upstream.Failure == Sub.Failure,
Upstream.Output == Sub.Input {
var retries = self.retries
let p = upstream
.catch { err -> AnyPublisher<Output, Failure> in
retries -= 1
return Fail(error: err)
.delay(for: retries > 0 ? interval : .zero, scheduler: scheduler)
.eraseToAnyPublisher()
}
.retry(self.retries)
p.subscribe(subscriber)
}
}
For convenience, you can create an operator, like you did in the question:
public extension Publisher {
func retryWithDelay<S>(
retries: Int,
delay: S.SchedulerTimeType.Stride,
scheduler: S
) -> RetryWithDelay<Self, S> where S: Scheduler {
RetryWithDelay(upstream: self,
retries: retries, delay: delay, scheduler: scheduler)
}
}
推荐阅读
- angular - 无法在 Angular 中看到添加到 HTTP 请求的标头
- javascript - 使用画布线的 JavaScript 画布悬停
- python - 对象实例中的 Numpy 数组,dtype 错误
- node.js - Node.js - 使用 createReadStream 和 createWriteStream 时内存使用率高
- c# - EF 错误:无法跟踪实体类型“对象”的实例,因为另一个实例
- flutter - 预期类型为“RootProvider”的值
- unity3d - 如何使爆炸仅影响 x 轴而不影响 y 轴统一
- python - 创建带有输出的条件循环
- c# - 以编程方式在本地 Azure DevOps 服务器工作项注释中为 Active Directory 用户帐户添加 @提及(2021 年 1 月)
- amazon-web-services - AWS Cognito Post 身份验证触发器获取身份 ID