Leí una publicación que dice que la mejor práctica para lidiar con RxSwift es solo pasar un error fatal a onError y pasar Result a onNext.
Tiene sentido para mí hasta que me doy cuenta de que ya no puedo lidiar con el reintento, ya que solo sucede en onError.
¿Cómo trato este problema?
Otra pregunta es, ¿cómo manejo las mezclas de reintentos globales y locales?
Un ejemplo sería el flujo de validación de recibos de iOS.
1, intente obtener el recibo localmente
2, si falla, solicite al servidor de Apple el último recibo.
3, envíe el recibo a nuestro backend para validarlo.
4, si tiene éxito, entonces todo el flujo se completa
5, si falla, verifique el código de error si se puede volver a intentar, luego regrese a 1.
y en el nuevo 1, obligará a solicitar un nuevo recibo del servidor de Apple. luego, cuando llegue a 5 nuevamente, todo el flujo se detendrá ya que este ya es el segundo intento. es decir, solo vuelva a intentarlo una vez.
Entonces, en este ejemplo, si uso una máquina de estado y no uso rx, terminaré usando una máquina de estado y compartiré un estado global como isSecondAttempt: Bool , shouldForceFetchReceipt: Bool , etc.
¿Cómo diseño este flujo en rx? con estos estados compartidos globales diseñados en el flujo.
Leí una publicación que dice que la mejor práctica para lidiar con RxSwift es solo pasar un error fatal a onError y pasar Result a onNext.
No estoy de acuerdo con ese sentimiento. Básicamente dice que solo debe usar onError si el programador cometió un error. Debe usar errores para rutas no felices o para abortar un procedimiento. Son como lanzar, excepto de forma asíncrona.
Aquí está su algoritmo como una cadena 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 } } }Estas son las funciones de soporte que utiliza lo anterior:
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) } }