Description
public void testSingleErrorWithRetry() throws Exception {
TestSubscriber testSubscriber = new TestSubscriber();
final RuntimeException myError = new RuntimeException("my error");
Single.error(myError)
.retryWhen(errorObservable -> Observable.empty())
.subscribe(testSubscriber);
testSubscriber.assertError(myError);
}
This test fails with the following exception:
java.lang.AssertionError: Exceptions differ; expected: java.lang.RuntimeException: my error, actual: java.util.NoSuchElementException: Observable emitted no items
at rx.observers.TestSubscriber.assertError(TestSubscriber.java:464)
at com.example.ExampleTest.testSingleErrorWithRetry(ExampleTest.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
... 17 more
Caused by: java.util.NoSuchElementException: Observable emitted no items
at rx.internal.operators.OnSubscribeSingle$1.onCompleted(OnSubscribeSingle.java:59)
at rx.internal.operators.OnSubscribeRedo$4$1.onCompleted(OnSubscribeRedo.java:326)
at rx.Observable$EmptyHolder$1.call(Observable.java:1123)
at rx.Observable$EmptyHolder$1.call(Observable.java:1120)
at rx.Observable.unsafeSubscribe(Observable.java:8314)
at rx.internal.operators.OnSubscribeRedo$4.call(OnSubscribeRedo.java:323)
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:80)
at rx.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:59)
at rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:320)
at rx.internal.operators.OnSubscribeRedo.call(OnSubscribeRedo.java:55)
at rx.Observable.unsafeSubscribe(Observable.java:8314)
at rx.internal.operators.OnSubscribeSingle.call(OnSubscribeSingle.java:83)
at rx.internal.operators.OnSubscribeSingle.call(OnSubscribeSingle.java:29)
at rx.Single$1.call(Single.java:93)
at rx.Single$1.call(Single.java:73)
at rx.Single.subscribe(Single.java:1665)
at com.example.ExampleTest.testSingleErrorWithRetry(ExampleTest.java:67)
... 22 more
This is the correct behavior as written in the documentation
If that Observable calls
onComplete
oronError
then retry will call onCompleted or onError on the child subscription.
The child subscription here is the subscriber in OnSubscribeSingle#call()
which converts an Observable
to a Single
. It throws this error in onCompleted
.
@Override
public void onCompleted() {
if (emittedTooMany) {
// Don't need to do anything here since we already sent an error downstream
} else {
if (itemEmitted) {
child.onSuccess(emission);
} else {
child.onError(new NoSuchElementException("Observable emitted no items"));
}
}
}
The behavior should be changed. The real child subscription before the Observable -> Single
conversion is a SingleSubscriber
which doesn't have the method onCompleted()
. Better onError
is called instead with the latest emitted error instead of the current NoSuchElementException
.
The docs should be updated to:
If that Observable calls
onComplete
oronError
then retry will callonError
on the child subscription.