I am new to RX and have been investigating error handling and the use of Retry; I have the following (yes I know it's not a 'real' unit test but it gives me place to fiddle!!) and was wondering how I go about keeping the Retry but be able to log any Exception?
[Test]
public void Test()
{
var scheduler = new TestScheduler();
var source = scheduler.CreateHotObservable(
new Recorded<Notification<long>>(10000000, Notification.CreateOnNext(0L)),
new Recorded<Notification<long>>(20000000, Notification.CreateOnNext(1L)),
new Recorded<Notification<long>>(30000000, Notification.CreateOnNext(2L)),
new Recorded<Notification<long>>(30000001, Notification.CreateOnError<long>(new Exception("Fail"))),
new Recorded<Notification<long>>(40000000, Notification.CreateOnNext(3L)),
new Recorded<Notification<long>>(40000000, Notification.CreateOnCompleted<long>())
);
source.Retry().Subscribe(
l => Console.WriteLine($"OnNext {l}"),
exception => Console.WriteLine(exception.ToString()), // Would be logging this in production
() => Console.WriteLine("OnCompleted"));
scheduler.Start(
() => source,
0,
TimeSpan.FromSeconds(1).Ticks,
TimeSpan.FromSeconds(5).Ticks);
}
Which results in...
OnNext 0
OnNext 1
OnNext 2
OnNext 3
OnCompleted
...which is exactly what I want to happen apart from fact I would like to log the Exception which occurs between 2 and 3.
Is there a way to allow the Subscriber to see the Exception in OnError (and log it) and then re-subscribe so it sees 3?
Thx!
Retry on Error The normal sequence may be broken by a temporary system failure or backend error. In these situations, we want to retry and wait until the sequence is fixed. Luckily, RxJava gives us options to perform exactly that. 4.1. Retry
Rx delivers the basic exception handling operators which you can use to compose complex and robust queries. In this chapter we have covered advanced error handling and some more resource management features from Rx.
In this chapter we see how they can be applied to observable sequences. Just like a catch in SEH (Structured Exception Handling), with Rx you have the option of swallowing an exception, wrapping it in another exception or performing some other logic.
RxJava also provides a fallback method that allows continuing the sequence with a provided Observable when an exception (but no error) is raised: As the code above shows, when an error does occur, the onExceptionResumeNext won't kick in to resume the sequence.
You could achieve that with this:
source
.Do(_ => { }, exception => Console.WriteLine(exception.ToString()), () => {})
.Retry()
.Subscribe(
l => Console.WriteLine($"OnNext {l}"),
// exception => Console.WriteLine(exception.ToString()), // Would be logging this in production
() => Console.WriteLine("OnCompleted")
);
Just to clarify what's going on here: OnError
is a terminating signal. If the error reached the subscription, that would terminate the rest of the stream. .Retry
terminates the subscription, swallows the OnError
, and then re-subscribes, melding the two subscriptions together. For example look at this:
source
.StartWith(-1)
.Retry()
.Subscribe(
l => Console.WriteLine($"OnNext {l}"),
() => Console.WriteLine("OnCompleted")
);
Your output would be
OnNext -1
OnNext 0
OnNext 1
OnNext 2
OnNext -1
OnNext 3
OnCompleted
The OnNext -1
shows up twice, because it shows up whenever you subscribe (which Retry
does after the OnError
.
Your test observable is frankly a bad test. It breaks the "Rx Contract" which is that notifications follow the following pattern:
OnNext* (OnCompleted | OnError)?
That is, 0 or more OnNext
notifications, followed by an optional OnError
or an optional OnCompleted
. No notifications of any type should follow either an OnError
or an OnCompleted
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With