question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Subscriber's onCompleted is not called when return Observable.empty() in retryWhen()

See original GitHub issue

I was testing out RxJava’s retryWhen() function an this problem occurred.

retryWhen()'s docs says:

Returns an Observable that emits the same values as the source observable with the exception of an onError. An onError notification from the source will result in the emission of a Throwable item to the Observable provided as an argument to the notificationHandler function. If that Observable calls onComplete or onError then retry will call onCompleted or onError on the child subscription. Otherwise, this Observable will resubscribe to the source Observable.

When I returns Observable.empty() in flatMap(), the subscriber’s onCompleted never gets called despite Observable.empty()'s docs says:

Returns an Observable that emits no items to the Observer and immediately invokes its onCompleted method.

If I replace Observable.empty() with Observable.error(new Exception("New Exception!")), the new exception is thrown to the subscriber’s onError(). It’s correct according to the retryWhen()'s docs.

Following is my code:

        Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                subscriber.onNext(10);
                sleep(1000);

                subscriber.onNext(20);
                sleep(1000);

                subscriber.onError(new Exception("My Exception!"));
            }
        }).retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
            @Override
            public Observable<?> call(Observable<? extends Throwable> observable) {
                return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                    @Override
                    public Observable<?> call(Throwable throwable) {
                        log("throwable = " + throwable.getMessage());
                        return Observable.empty();
//                        return Observable.error(new Exception("New Exception!"));
                    }
                });
            }
        }).subscribeOn(Schedulers.newThread()).subscribe(new Subscriber<Object>() {
            @Override
            public void onCompleted() {
                log("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                log("onError: " + e.getMessage());
            }

            @Override
            public void onNext(Object integer) {
                log("onNext: " + integer);
            }
        });
    private void sleep(long duration) {
        try {
            Thread.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void log(String s) {
        Log.e("linhln", s);
    }

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:1
  • Comments:11 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
mrleolinkcommented, Nov 26, 2015

Hi @akarnokd, I’m quite new to Reactive so I don’t get your trick.

So to make it simpler, I have this piece of code. The problem is onCompleted is not called despite Observable.empty(), could you please show me how to apply the trick to make onCompleted gets called.

        Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                subscriber.onNext(10);
                sleep(1000);

                subscriber.onNext(20);
                sleep(1000);

                subscriber.onError(new Exception("My Exception!"));
            }
        })
        .retryWhen(new Func1<Observable<? extends Throwable>, Observable<?>>() {
            int count = 0;
            @Override
            public Observable<?> call(Observable<? extends Throwable> observable) {
                return observable.flatMap(new Func1<Throwable, Observable<?>>() {
                    @Override
                    public Observable<?> call(Throwable throwable) {
                        if (++count < 3) {
                            log(String.format("Because of %s: retrying after %d second(s)...", throwable.getMessage(), count));
                            return Observable.timer(count, TimeUnit.SECONDS);
                        }

                        // just complete
                        return Observable.empty();
                    }
                });
            }
        })
        .subscribeOn(Schedulers.newThread()).subscribe(new Subscriber<Object>() {
            @Override
            public void onCompleted() {
                log("onCompleted");
            }

            @Override
            public void onError(Throwable e) {
                log("onError: " + e.getMessage());
            }

            @Override
            public void onNext(Object integer) {
                log("onNext: " + integer);
            }
        });
1reaction
stealthcodecommented, Nov 25, 2015

Oh I see. Because the observable passed in as the argument could still emit a new Throwable (that may result in a flatMap of more emissions). Yes this makes more sense. You would have to complete the outer observable in order to ensure that no further inner observables can be merged.

@akarnokd @abersnaze If we begin to create observables that have limited operator sets then it would be good to pass in an observable that did not have flatMap to the notification handler (in 2.x of course).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why didn't child subscriber's onComplete() method invoke ...
according to the retryWhen() doc: Returns an Observable that emits the same values as the source observable with the exception of an onError....
Read more >
RxJava's repeatWhen and retryWhen, explained
The input is Observable<Void> , since onCompleted has no type. The notificationHandler (i.e. Func1 ) is only called once per subscription. This ...
Read more >
Subscriptions - Apollo GraphQL Docs
When Apollo Client executes the OnCommentAdded subscription, it establishes a connection to your GraphQL server and listens for response data. Unlike with a ......
Read more >
RxJava — Handling Errors Like a Pro | by TC Wang - Medium
Two of the most basic but useful Observers are retry() and retryWhen() . Disclaimer: As we mentioned previously, not all of the Observers...
Read more >
Maybe (RxJava Javadoc 3.1.5) - ReactiveX
printStackTrace(); } @Override public void onComplete() { System.out.println("Done! ... Returns a Maybe that invokes a subscriber's onError method when the ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found