Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RX.Net : Use Retry but log any Exception

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!

like image 510
inthegarden Avatar asked Jun 06 '17 13:06

inthegarden


People also ask

Why do I need to retry in RxJava?

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

What is exception handling in RX?

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.

How do you handle exceptions in observable sequences with 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.

What is the fallback method for exception handling in RxJava?

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.


1 Answers

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.

like image 71
Shlomo Avatar answered Oct 16 '22 19:10

Shlomo