URLSession dataTaskPublisher在延迟特定错误后重试 [英] URLSession dataTaskPublisher retry after delay on specific errors

查看:54
本文介绍了URLSession dataTaskPublisher在延迟特定错误后重试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要执行的操作是重新发送针对特定类型错误的请求.假设发生超时错误,具体来说,我想在3秒的延迟后重试该请求.显然,如果请求成功执行,我不希望有任何延迟.

What I'm trying to do is to resend a request for specific kinds of errors. Let's say for the timeout error specifically I want to retry the request after 3 seconds delay. Obviously, I don't want any delays if the request executed successfully.

我正在此处

var cancellables = Set<AnyCancellable>()

let url = URL(string: "https://www.apple.com")!
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 1
sessionConfiguration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData

let publisher = URLSession(configuration: sessionConfiguration).dataTaskPublisher(for: url).share()

let head = publisher.print().tryCatch { error -> AnyPublisher<(data: Data, response: URLResponse), URLError> in
    switch error {
    case URLError.timedOut:
        print("I'm in URLError.timedOut case")
        return publisher.delay(for: 3, scheduler: DispatchQueue.main).eraseToAnyPublisher()

    default:
        print("I'm in default case")
        throw error
    }
}.retry(3)

head.map { data, response in
    return data
}.sink(receiveCompletion: {
    print("completion \($0)")
}, receiveValue: {
    print("value \($0)")
}).store(in: &cancellables)

出于测试目的,我为URLSession设置了1秒超时间隔,并限制了我的网络连接,当整个管道在大约10秒内结束时,我希望看到4个失败的请求.但是我实际看到的只是一个失败的请求,并且在一段时间后打印完成但失败.在我看来,我确实每三秒钟从 tryCatch 运算符返回 publisher ,但是由于某种原因,它并没有发送新的请求.

For the test purpose I set 1 second timeout interval for the URLSession and throttle my network connection expecting to see 4 failed requests when the whole pipeline finishes in about 10 seconds. But what I actually see is just one failed request and printed completion with a failure after some time. To me it seems like I do return publisher from tryCatch operator every three seconds but for some reason it doesn't happen to send a new request.

我想念什么?有没有其他解决方案可以解决这个问题?

What am I missing? Are there any alternative solutions to this problem?

更新14/05/2020

UPDATED 14/05/2020

我在 tryCatch 之前添加了 print()运算符,并在闭包内部进行了一些打印.我在控制台中看到的是这个

I added print() operator right before tryCatch, and some printing inside closure. What I see in console is this

receive subscription: (Multicast)
request unlimited
receive error: (URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."...))
I'm in URLError.timedOut case
receive subscription: (Multicast)
request unlimited
receive error: (URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." ...))
I'm in URLError.timedOut case
receive subscription: (Multicast)
request unlimited
receive error: (URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." ...))
I'm in URLError.timedOut case
receive subscription: (Multicast)
request unlimited
receive error: (URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." ...))
I'm in URLError.timedOut case
completion failure(Foundation.URLError(_nsError: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out."...))

但是我在Charles http代理中看到的正是一个请求,该请求是在重试之前发送的.

But what I see in my Charles http proxy is exactly one request, the one that's sent before retries

推荐答案

我做了一些测试,您的问题似乎出在这行上:

I did some testing and your problem appears to be on this line:

let publisher = URLSession(configuration: sessionConfiguration).dataTaskPublisher(for: url).share()

通过使用 share()重放或共享数据任务发布者的结果.因此,尽管您的重试逻辑工作正常,但每次都会重播第一个请求的结果.如果删除 share(),则在出现 URLError.timedOut 的情况下,将发出新请求.

By using share() you replay, or share the result of the data task publisher. So while your retry logic works fine, the result of the first request will be replayed every time. If you remove the share() a new request will be made in case of URLError.timedOut.

如果需要重播/共享,则可以在重试之后添加它,这样您创建的数据任务发布者就不会重播初始尝试的结果.

If you need the replay / sharing then you can add that after your retry so the data task publisher you create doesn't replay the result of the initial attempt.

这篇关于URLSession dataTaskPublisher在延迟特定错误后重试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆