Denathan
Denathan

Reputation: 161

RxJava2 - How to retry everytime except if it's TimeoutException?

I've got a chain of Observables and at the end of it, I'm writing a command to the device via Bluetooth and I'm waiting for the notification. There's a case, where it can wait here forever so I would like to use timeout - easy.

But the problem is that, I want to retry every time any other problem occurred, it should be terminated only if timeout happen - otherwise it should retry. Also, if we go down through the chain, we will meet other retries that also should have the same behavior. Timeout exception should be pushed back to the higher layer(interactor in my case).

I thought about retryWhen but I'm not sure how to use it properly in that case.

.retryWhen { it.filter { throwable -> throwable !is TimeoutException } }

Also, it's hard to write tests for that so it makes it harder for me to find the right solution.

Upvotes: 1

Views: 1006

Answers (1)

anshul
anshul

Reputation: 992

Please try this following approach which i am using for my project.

Create a class (It is a java class you can change it into kotlin if required)

public class RetryWithDelay implements Function<Observable<? extends Throwable>, Observable<?>> {
private static final String TAG = "RetryWithDelay";

private final int maxRetries;
private final int retryDelayInMinutes;
private int retryCount;



public RetryWithDelay(final int maxRetries, final int retryDelayInMinutes) {
    this.maxRetries = maxRetries;
    this.retryDelayInMinutes = retryDelayInMinutes;
    this.retryCount = 0;
}

@Override
public Observable<?> apply(Observable<? extends Throwable> attempts) {
    return attempts.flatMap(new Function<Throwable, Observable<?>>() {
        @Override
        public Observable<?> apply(Throwable throwable) {
            if (throwable instanceof TimeoutException) {
                return Observable.error(throwable);
            }

            if (++retryCount < maxRetries) {
                // When this Observable calls onNext, the original
                // Observable will be retried (i.e. re-subscribed).
                return Observable.timer(retryDelayInMinutes, TimeUnit.MINUTES);
            }

            // Max retries hit. Just pass the error along.
            return Observable.error(throwable);
        }
    });
}}

Inside apply method, it will check if the exception is instance of TimeOut , it will throw an error else it will keep retrying for the maxRetries you want.

And pass this class as below

  .retryWhen (new RetyWithDelay(3,5)) 

Where it will retry for 3 times every 5 mins.

Upvotes: 1

Related Questions