Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll see how to use retry with delay in RxJava. When working with Observable, it is quite likely to get an error instead of a success. In such cases, we can use retry with delay to reattempt after some time.

2. Project Setup

To begin this, let’s create a Maven or a Gradle project. Here, we’re using a Maven-based project. Let’s add the rxjava dependency to our pom.xml file:

<dependency>
    <groupId>io.reactivex.rxjava2</groupId>
    <artifactId>rxjava</artifactId>
    <version>2.2.21</version>
</dependency>

The dependency can be found on the Maven Central Page.

3. Retry in the Observable Lifecycle

Retry is used when an Observable source emits an error. This is a resubscription to the source in the hopes of getting completed without errors in the next attempt. Therefore, retry() and its other variants come into the picture only when the Observable emits an error.

3.1. Overloaded Variants of Retry

Apart from the retry() method discussed in the above section, RxJava provides two overloaded variants, retry(long) and retry(Func2).

The retry(long) returns an Observable that mirrors the source Observable. We resubscribe to this mirror only as long as it calls onError the specified number of times.

The retry(Func2) method takes a function that accepts a Throwable as input and produces a boolean as output. Here, we resubscribe to the mirror only if it returns true for the specific Exception and the retry count.

3.2. RetryWhen vs Retry

The retryWhen(Func1) provides us with an option to include custom logic to determine whether or not we should resubscribe to the mirror of the original Observable. This method accepts a function that takes the exception thrown by the onError handler.

If the function emits an item, we resubscribe to the mirror, while we don’t if it produces an onError notification.

4. Code Examples

Let’s now watch these concepts in action with the help of a few code snippets.

4.1. Successful Observable

If an Observable call succeeds, then the Observer’s onNext method is invoked. Let’s see an example:
@Test
public void givenObservable_whenSuccess_thenOnNext(){
    Observable.just(remoteCallSuccess())
        .subscribe(success -> {
            System.out.println("Success");
            System.out.println(success);
        }, err -> {
            System.out.println("Error");
            System.out.println(err);
        });
}

The method remoteCallSuccess() completes successfully and returns a String. In this case, the onNext() method of the subscriber is invoked, printing success messages.

4.2. Erroneous Observable

Let’s introduce a new utility function called remoteCallError() that mocks calling a remote server. This method is vulnerable to errors. Therefore, our retryWhen logic would kick in:
@Test
public void givenObservable_whenError_thenOnError(){
    Observable.just(remoteCallError())
        .subscribe(success -> {
            System.out.println("Success");
            System.out.println(success);
        }, err -> {
            System.out.println("Error");
            System.out.println(err);
        });
}

In this case, the remoteCallError() method causes an error. Therefore, the onError() method of the subscriber gets called. Consequently, error messages get printed.

4.3. Retrying with Delay

We can add a delay during the resubscription process:
@Test
public void givenError_whenRetry_thenCanDelay(){
    Observable.just(remoteCallError())
        .retryWhen(attempts -> {
            return attempts.flatMap(err -> {
                if (customChecker(err)) {
                    return Observable.timer(5000, TimeUnit.MILLISECONDS);
                } else {
                    return Observable.error(err);
                }
            });
        });
}

Similar to the previous case, the remoteCallError() method causes an error. Here, however, instead of notifying the observer’s onError() method, we give this Observable a chance to resubcribe. For this, we pass the exception to a customChecker() method, which returns a boolean. If the response is true, we return a new Observable with a delay of 5000 milliseconds (5 seconds). Otherwise, we return an error and notify the observer.

5. Conclusion

In this tutorial, we saw how to use retryWhen and some of its related functions. We understood the cases under which retry and retryWhen help us solve our issues. The source code is available over on GitHub.
Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Junit (guide) (cat=Reactive)
1 Comment
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.