Reputation: 267
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?
Upvotes: 6
Views: 1387
Reputation: 14350
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
.
Upvotes: 8