Как использовать retry, когда только 3 раза потом сдаешься - PullRequest
0 голосов
/ 01 июля 2018

Я хочу отфильтровать, когда во время выполнения какой-либо функции верхней цепочки возникает определенное исключение, и попытаться повторить весь процесс только 3 раза, тогда, если он все еще не сработал, то сдавайтесь. Я пришел к чему-то вроде этого:

   val disposable = someFunction(someParameter, delay, subject)
    .flatMapCompletable { (parameter1, parameter2) ->
      anotherFunction(parameter1, parameter2, subject)
    }
    .retryWhen { throwable ->
      throwable.filter {
        it.cause?.cause is ExampleException1
            || it.cause?.cause is ExampleException2
            || it.cause is ExampleException3
      }
    }
    .andThen(someStuff())
    .subscribe({
      Timber.d("Finished!")
    }, {
      Timber.d("Failed!")
    })

Как это сделать правильно?

Ответы [ 2 ]

0 голосов
/ 01 июля 2018

Вы можете использовать zipWith с range для достижения этой цели.

.retryWhen { errors -> errors.zipWith(Observable.range(1, 3), { _, i -> i }) }

Оператор retryWhen предоставляет вам поток всех ошибок от вашего исходного издателя. Здесь вы заархивируете их числами 1, 2, 3. Поэтому результирующий поток будет излучать 3 next, а затем complete. Вопреки тому, что вы думаете, это повторяет подписку только дважды, поскольку complete, испускаемый сразу после третьего next, приводит к завершению всего потока.

Вы можете расширить это, повторив попытку только для некоторых ошибок, в то же время немедленно потерпев неудачу для других. Например, если вы хотите повторить попытку только для IOException, вы можете расширить приведенное выше решение до:

.retryWhen { errors -> errors
  .zipWith(Observable.range(1, 3), { error, _ -> error })
  .map { error -> when (error) {
    is IOException -> error
    else -> throw error
  }}
}

Поскольку map не может генерировать проверенное исключение в Java, пользователи Java могут использовать flatMap для той же цели.

0 голосов
/ 01 июля 2018

Я думаю, что то, что вы пытаетесь сделать, может быть достигнуто исключительно с помощью retry:

val observable = Observable.defer {
    System.out.println("someMethod called") 
    val result1 = 2 // some value from someMethod()
    Observable.just(result1)
}

observable.flatMap { result ->
    // another method is called here but let's omit it for the sake of simplicity and throw some exception
    System.out.println("someMethod2 called") 
    throw IllegalArgumentException("Exception someMethod2")
    Observable.just("Something that won't be executed anyways")
}.retry { times, throwable ->
            System.out.println("Attempt# " + times)
            // if this condition is true then the retry will occur
            times < 3 && throwable is IllegalArgumentException
        }.subscribe(
                { result -> System.out.println(result) },
                { throwable -> System.out.println(throwable.localizedMessage) })

Выход:

SomeMethod называется

someMethod2 называется

Попытка # 1

некий метод называется

SomeMethod2 называется

Попытка # 2

SomeMethod называется

SomeMethod2 называется

Попытка # 3

Исключение someMethod2

Поскольку someMethod2 всегда выбрасывает Exception, после 3 попыток Exception someMethod2 печатается в onError наблюдателя.

...