处理RxSwift重试和错误处理的最佳实践是什么

问题描述 投票:1回答:1

我读了一些帖子说处理RxSwift的最佳做法是只将致命错误传递给onError并将Result传递给onNext。

这对我有意义,直到我意识到我不能再处理重试,因为它只发生在onError上。

我该如何处理这个问题?

另一个问题是,我如何一起处理全局和本地重试混合?

一个例子是iOS收据验证流程。

1,尝试在本地获取收据

2,如果失败,请向Apple服务器索取最新收据。

3,将收据发送到我们的后端进行验证。

4,如果成功,那么整个流程完成

5,如果失败,检查错误代码是否可以重试,然后返回1。

在新的1中,它将强制要求苹果服务器的新收据。然后当它再次达到5时,整个流程将停止,因为这已经是第二次尝试了。意思是只重试一次。

所以在这个例子中,如果使用状态机而不使用rx,我将最终使用状态机并共享一些全局状态,如isSecondAttempt: BoolshouldForceFetchReceipt: Bool等。

如何在rx中设计此流程?在流程中设计这些全局共享状态。

ios swift error-handling rx-swift
1个回答
1
投票

我读了一些帖子说处理RxSwift的最佳做法是只将致命错误传递给onError并将Result传递给onNext。

我不同意这种观点。基本上说,如果程序员犯了错误,你应该只使用onError。您应该将错误用于不满意的路径或中止过程。它们就像投掷一样,只是以异步的方式。

这是你的算法作为Rx链。

enum ReceiptError: Error {
    case noReceipt
    case tooManyAttempts
}

struct Response { 
    // the server response info
}

func getReceiptResonse() -> Observable<Response> {
    return fetchReceiptLocally()
        .catchError { _ in askAppleForReceipt() }
        .flatMapLatest { data in
            sendReceiptToServer(data)
        }
        .retryWhen { error in
            error
                .scan(0) { attempts, error in
                    let max = 1
                    guard attempts < max else { throw ReceiptError.tooManyAttempts }
                    guard isRetryable(error) else { throw error }
                    return attempts + 1
                }
        }
}

以下是上述用途的支持功能:

func fetchReceiptLocally() -> Observable<Data> {
    // return the local receipt data or call `onError`
}

func sendReceiptToServer(_ data: Data) -> Observable<Response> {
    // send the receipt data or `onError` if the server failed to receive or process it correctly.
}

func isRetryable(_ error: Error) -> Bool {
    // is this error the kind that can be retried?
}

func askAppleForReceipt() -> Observable<Data> {
    return Observable.just(Bundle.main.appStoreReceiptURL)
        .map { (url) -> URL in
            guard let url = url else { throw ReceiptError.noReceipt }
            return url
        }
        .observeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
        .map { try Data(contentsOf: $0) }
}
© www.soinside.com 2019 - 2024. All rights reserved.