M Rajoy
M Rajoy

Reputation: 4094

Exponential backoff in Kotlin with RxJava2

I am trying to do an exponential retry for a request, so that if the request fails (i.e. your internet is down) the app retries endlessly until it works (for the amount of time the app is in the foreground)

I tried with this solution

    public class RetryWithDelay implements Function<Observable<? extends Throwable>, Observable<?>> {
    private final int maxRetries;
    private final int retryDelayMillis;
    private int retryCount;

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

    @Override
    public Observable<?> apply(final Observable<? extends Throwable> attempts) {
        return attempts
                .flatMap(new Function<Throwable, Observable<?>>() {
                    @Override
                    public Observable<?> apply(final Throwable throwable) {
                        if (++retryCount < maxRetries) {
                            // When this Observable calls onNext, the original
                            // Observable will be retried (i.e. re-subscribed).
                            return Observable.timer(retryDelayMillis,
                                    TimeUnit.MILLISECONDS);
                        }

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

But when I try to convert this to kotlin it says Function only takes one generic parameter.

Upvotes: 1

Views: 1359

Answers (1)

akarnokd
akarnokd

Reputation: 69997

I copy-pasted the Java code into IntelliJ and it did half the work for me:

import java.util.concurrent.TimeUnit
import io.reactivex.functions.Function
import io.reactivex.*

class RetryWithDelay(private val maxRetries: Int, private val retryDelayMillis: Long) : Function<Observable<Throwable>, Observable<Long>> {

    override fun apply(attempts: Observable<Throwable>): Observable<Long> {
        return attempts
                .flatMap(object : Function<Throwable, Observable<Long>> {

                    private var retryCount: Int = 0

                    override fun apply(throwable: Throwable): Observable<Long> {
                        return if (++retryCount < maxRetries) {
                            // When this Observable calls onNext, the original
                            // Observable will be retried (i.e. re-subscribed).
                            Observable.timer(retryDelayMillis,
                                    TimeUnit.MILLISECONDS)
                        } else Observable.error<Long>(throwable)

                        // Max retries hit. Just pass the error along.
                    }
                })
    }
}

Note that the retryCount has been moved into the inner flatMap so that it is not shared between multiple Observers.

Upvotes: 4

Related Questions