This is an easy program to introduce the Reactive Framework. But I want to try the error handler, by modifying the program to be:
var cookiePieces = Observable.Range(1, 10);
cookiePieces.Subscribe(x =>
{
Console.WriteLine("{0}! {0} pieces of cookie!", x);
throw new Exception(); // newly added by myself
},
ex => Console.WriteLine("the exception message..."),
() => Console.WriteLine("Ah! Ah! Ah! Ah!"));
Console.ReadLine();
In this sample the follwing overload is used.
public static IDisposable Subscribe<TSource>(
this IObservable<TSource> source,
Action<TSource> onNext,
Action<Exception> onError,
Action onCompleted);
I hoped I would see the exception message printed, but the console application crashed. What is the reason?
The exception handler is used for exceptions created in the observable itself, not by the observer.
An easy way to provoke the exception handler is something like this:
using System;
using System.Linq;
class Test
{
static void Main(string[] args)
{
var xs = Observable.Range(1, 10)
.Select(x => 10 / (5 - x));
xs.Subscribe(x => Console.WriteLine("Received {0}", x),
ex => Console.WriteLine("Bang! {0}", ex),
() => Console.WriteLine("Done"));
Console.WriteLine("App ending normally");
}
}
Output:
Received 2
Received 3
Received 5
Received 10
Bang! System.DivideByZeroException: Attempted to divide by zero.
at Test.<Main>b__0(Int32 x)
at System.Linq.Observable.<>c__DisplayClass35a`2.<>c__DisplayClass35c.<Select
>b__359(TSource x)
App ending normally
In the Rx library, any user code passed into an operator that works on IObservable (Select, Where, GroupBy etc...) will be caught and send to the OnError handler of observers subscribed to the observable. The reason these are handled is that they are part of the computation.
Exceptions occurring in Observer code will have to be handled by the user. As they're at the end of the computation, it is unclear to Rx how to handle these.
Does it really crash or jumps Visual Studio into and shows you that an exception happened? If the second is true, you should take a look into Debug - Exception within the menu bar and deselect everything on the right.
Related
Recently I become aware that the Rx Finally operator behaves in a way which, at least for me, is unexpected. My expectation was that any error thrown by the finallyAction would be propagated to the operator's observers downstream. Alas this is not what happens. In the reality the operator first propagates the completion (or the failure) of the antecedent sequence to its observers, and then invokes the action, at a point in time when it's not possible to propagate a potential error thrown by the action. So it throws the error on the ThreadPool, and crashes the process. Which is not only unexpected, but also highly problematic. Below is a minimal demonstration of this behavior:
Observable
.Timer(TimeSpan.FromMilliseconds(100))
.Finally(() => throw new ApplicationException("Oops!"))
.Subscribe(_ => { }, ex => Console.WriteLine(ex.Message),
() => Console.WriteLine("Completed"));
Thread.Sleep(1000);
Outcome: Unhandled exception (Fiddle)
The exception thrown by the Finally lambda is not handled by the Subscribe:onError handler, as it would be desirable.
This feature (I am tempted to call it a flaw) limits severely the usefulness of the Finally operator in my eyes. Essentially I can only use it when I want to invoke an action that is expected to never fail, and if it fails it would indicate a catastrophic corruption of the application's state, when no recovery is possible. I could use it for example to Release a SemaphoreSlim (like I've done here for example), which can only fail if my code has a bug. I am OK with my app crashing in this case. But I've also used it recently to invoke an unknown action supplied by the caller, an action that could potentially fail, and crashing the app in this case is unacceptable. Instead, the error should be propagated downstream. So what I am asking here is how to implement a Finally variant (let's call it FinallySafe) with identical signature, and the behavior specified below:
public static IObservable<TSource> FinallySafe<TSource>(
this IObservable<TSource> source, Action finallyAction);
The finallyAction should be invoked after the source sequence has emitted an OnCompleted or an OnError notification, but before this notification is propagated to the observer.
If the finallyAction invocation completed successfully, the original OnCompleted/OnError notification should be propagated to the observer.
If the finallyAction invocation failed, an OnError notification should be propagated to the observer, containing the error that just occurred. In this case the previous error, the one that may have caused the source to complete with failure, should be ignored (not propagated).
The finallyAction should also be invoked when the FinallySafe is unsubscribed before the completion of the source. When a subscriber (observer) disposes a subscription, the finallyAction should by invoked synchronously, and any error should be propagated to the caller of the Dispose method.
If the FinallySafe is subscribed by multiple observers, the finallyAction should be invoked once per subscription, independently for each subscriber, following the rules above. Concurrent invocations are OK.
The finallyAction should never be invoked more than once per subscriber.
Validation: replacing the Finally with the FinallySafe in the code snippet above, should result to a program that doesn't crash with an unhandled exception.
Alternative: I am also willing to accept an answer that provides a reasonable explanation about why the behavior of the built-in Finally operator is better than the behavior of the custom FinallySafe operator, as specified above.
Finally gets called after the sequence has ended, and since the Rx contract only allows one OnError or OnCompleted it can't issue a second one.
But, if you replace the Finally with Do you can get the behaviour that you want.
Try this code:
Observable
.Timer(TimeSpan.FromMilliseconds(100))
.Do(_ => { }, () => throw new ApplicationException("Oops!"))
.Subscribe
(_ => { },
ex => Console.WriteLine(ex.Message),
() => Console.WriteLine("Completed"));
Thread.Sleep(TimeSpan.FromMilliseconds(1000));
That operates as you expect it to.
I get this output:
Oops!
If you want to run something at unsubscribe, then use this extension method:
public static class Ext
{
public static IObservable<T> Unsubscribed<T>(this IObservable<T> source, Action unsubscribed) =>
Observable.Create<T>(o =>
new CompositeDisposable(source.Subscribe(o), Disposable.Create(unsubscribed)));
}
Here's an example of its use:
var source = Observable.Never<int>();
var subscription =
source
.Unsubscribed(() => Console.WriteLine("Unsubscribed"))
.Subscribe();
subscription.Dispose();
That outputs:
Unsubscribed
Here is an implementation of the FinallySafe operator, having the behavior specified in the question:
/// <summary>
/// Invokes a specified action after the source observable sequence terminates
/// successfully or exceptionally. The action is invoked before the propagation
/// of the source's completion, and any exception thrown by the action is
/// propagated to the observer. The action is also invoked if the observer
/// is unsubscribed before the termination of the source sequence.
/// </summary>
public static IObservable<T> FinallySafe<T>(this IObservable<T> source,
Action finallyAction)
{
return Observable.Create<T>(observer =>
{
var finallyOnce = Disposable.Create(finallyAction);
var subscription = source.Subscribe(observer.OnNext, error =>
{
try { finallyOnce.Dispose(); }
catch (Exception ex) { observer.OnError(ex); return; }
observer.OnError(error);
}, () =>
{
try { finallyOnce.Dispose(); }
catch (Exception ex) { observer.OnError(ex); return; }
observer.OnCompleted();
});
return new CompositeDisposable(subscription, finallyOnce);
});
}
The finallyAction is assigned as the Dispose action of a Disposable.Create disposable instance, in order to ensure that the action will be invoked at most once. This disposable is then combined with the disposable subscription of the source, by using a CompositeDisposable instance.
As a side note, I would like to address the question if we could go even further, and propagate downstream a possible error of the finallyAction during the unsubscription. This could be desirable in some cases, but unfortunately it's not possible. First and foremost doing so would violate a guideline, found in The Observable Contract document, that states:
When an observer issues an Unsubscribe notification to an Observable, the Observable will attempt to stop issuing notifications to the observer. It is not guaranteed, however, that the Observable will issue no notifications to the observer after an observer issues it an Unsubscribe notification.
So such an implementation would be non-conforming. Even worse, the Observable.Create method enforces this guideline, by muting the observer immediately after the subscription is disposed. It does so by encapsulating the observer inside an AutoDetachObserver wrapper. And even if we tried to circumvent this limitation by implementing an IObservable<T> type from scratch, any built-in operator that could be attached after our non-conforming Finally operator would mute our post-unsubscription OnError notification anyway. So it's just not possible. An error during the unsubscription cannot be propagated to the subscriber that just requested to unsubscribe.
I read the documentation and now I'm sure. The finally-operator will be called after the completition and should not throw any exception.
Compared to non-reactive programming:
StreamReader file = new StreamReader("file.txt");
string ln;
try {
while ((ln = file.ReadLine()) != null) {
Console.WriteLine(ln);
}
}
finally {
// avoid to throw an exception inside of finally!
if (file != null) {
file.close();
}
}
It is important to not throw an exception inside of finally.
Here is an example howto use it correctly (fiddle):
using System;
using System.Reactive.Linq;
using System.Threading;
public class Program
{
public static void Main()
{
Observable
.Range(1,5) // simulates stream-reader
.Finally(() => Console.WriteLine("Close streamreader"))
.Do(i => {
if (i == 5) {
throw new ApplicationException("Oops!"); // simulates IO-error
}
Console.WriteLine("Read " + i);
})
.Subscribe(_ => { }, ex => Console.WriteLine(ex.Message),
() => Console.WriteLine("Completed"));
Thread.Sleep(1000);
}
}
I'm not sure what you are trying to do (and I'm pretty new to c# reactive), but I think you are using not the right operator.
Edit
But you can patch it, if you want. In this article, they do something familar.
http://introtorx.com/Content/v1.0.10621.0/11_AdvancedErrorHandling.html
i have this code(sample source code from sample code)
i change a little this code for get exception with onError like :
IObservable<int> source = Observable.Range(1, 10);
IDisposable subscription = source.Subscribe<int>(
onNext =>
{
int zero = 0; //added this code
var div = onNext / zero; //and this code for get execption
},
onError =>
{
Console.WriteLine("OnError: {0}", onError.Message); // This code never runs
});
subscription.Dispose();
how to set exception to onError?
The onError here is supposed to catch exception errors emitted by source, not by your callback onNext.
I would say the try ... catch inside onNext is the usual way to go here, though it's understandable that you want to reuse your error handling in onError.
If you want to force this pattern here, what you could do is to pipe your observable to another that executes the code you want to catch, with a Do for instance, and subscribe to the result observable.
something like :
IObservable<int> source = Observable.Range(1, 10);
IDisposable subscription = source.Do(_ =>
{
// Here goes the code you had in your 'onNext' originally
throw new Exception("Throw exception manually for test purposes.");
})
.Subscribe(
_ => { /* nothing to do */ },
error =>
{
Console.WriteLine("OnError: {0}", error.Message);
}
);
Related Q&A : How to handle exceptions in OnNext when using ObserveOn?
(I don't think this is an exact duplicate, but a part overlaps with this question, IMO)
My goal here is to spool all items/notifications going from IObservable<T> for future subscribers.
E.g. if someone subscribes on a message stream, first he receives all messages which came prior to the subscription. Then he starts receiving new messages, whenever there are any. This should occur seamlessly, without repetitions and losses on the "boundary" between old and new messages.
I came up with following extension method:
public static IObservable<T> WithHistory<T>(this IObservable<T> source)
{
var accumulator = new BlockingCollection<T>();
source.Subscribe(accumulator.Add);
return accumulator
.GetConsumingEnumerable()
.ToObservable()
.SubscribeOn(ThreadPoolScheduler.Instance);
}
As far as I tested it, it works:
class Generator<T>
{
event Action<T> onPush;
public IObservable<T> Items =>
Observable.FromEvent<T>(d => onPush += d, d => onPush -= d);
public void Push(T item) => onPush?.Invoke(item);
}
...
private static void Main()
{
var g = new Generator<int>();
var ongoingItems = g.Items;
var allItems = g.Items.WithHistory();
g.Push(1);
g.Push(2);
ongoingItems.Subscribe(x => Console.WriteLine($"Ongoing: got {x}"));
allItems.Subscribe(x => Console.WriteLine($"WithHistory: got {x}"));
g.Push(3);
g.Push(4);
g.Push(5);
Console.ReadLine();
}
The result:
Ongoing: got 3
Ongoing: got 4
Ongoing: got 5
WithHistory: got 1
WithHistory: got 2
WithHistory: got 3
WithHistory: got 4
WithHistory: got 5
However, using BlockingCollection<T> seems to be an overkill. Also the method above does not support completion, error handling and would cause deadlocks without .SubscribeOn(ThreadPoolScheduler.Instance).
Is there any better way to achieve it, without the described flaws?
Best way to do it is with .Replay()
void Main()
{
var g = new Generator<int>();
var ongoingItems = g.Items;
var allItems = g.Items.Replay().RefCount();
using(var tempSubscriber = allItems.Subscribe())
{
g.Push(1);
g.Push(2);
ongoingItems.Subscribe(x => Console.WriteLine($"Ongoing: got {x}"));
allItems.Subscribe(x => Console.WriteLine($"WithHistory: got {x}"));
g.Push(3);
g.Push(4);
g.Push(5);
Console.ReadLine();
}
}
.Replay().RefCount() produces an observable that will keep an internal queue for replaying, as long as there's a subscriber. If you have a persistent subscriber though (like your solution does in the WithHistory method), you have a memory leak. The best way to get around this is to have a temporary subscriber which automatically disconnects after you're no longer interested in the history.
Consider this Observable:
_listener = Observable.Defer(() => _deviceTypeProvider.GetDeviceTypes().ToObservable()
.SelectMany(CreateUdpListener, CreateMessage)
.OfType<DeviceMessage>()
.SelectMany(InjectTestMode)
.OfType<DeviceMessage>()
.Do(async message => await PublishMessage(message)))
.Retry()
.Subscribe(OnMessageReceive, OnError, OnComplete);
This works fine except when there is an exception thrown in either CreateMessage or InjectTestMode.
I'd like the Observable to skip the item in the sequence which generated the exception and carry on.
I've read about Catch but the example I found allow you to start a new Observable and I would like to carry on with the one I have.
At the moment the entire sequence restarts which includes the UDP ports which I'd like to avoid if possible.
[Update]
A colleague and I re-read some of the comments about using IEnumerable<IObservable<>> or IObservable<IObservable<>> and came up with this which works! But is it right/best practice?
In the event of an exception in the inner observable I'm wondering if it will only drop the packets from the ReceiveAsync event that was in flight.
var listeners = Observable.Defer(() => _deviceTypeProvider.GetDeviceTypes()
.ToObservable()
.Select(UdpListener)
.SelectMany(listener =>
{
return Observable.Defer(() => Observable
.FromAsync(listener.UdpClient.ReceiveAsync)
.Where(x => x.Buffer.Length > 0)
.Repeat()
.Select(result => CreateMessage(listener.DeviceType, result))
.SelectMany(InjectTestMode)
.OfType<DeviceMessage>()
.Do(async message => await PublishMessage(message)))
.Retry();
})).Retry();
_listener = listeners.Subscribe(OnMessageReceive, OnError, OnComplete);
The documentation for IObservable<T> specifies that a sequence must match this grammar:
OnNext* (OnCompleted|OnError)
There cannot be any more values emitted after an exception or completion. If you manually make an observable that violates this grammar, you can expect undefined behavior when you use any of the existing Rx operators. Not good!
Model your query as an IEnumerable<IObservable<T>> or IObservable<IObservable<T>> if you want to get retry behavior, where the outer IEnumerable<*> or IObservable<*> never throws.
Make some static extension function, pass delegate to it, and wrap it up into try{}catch{} inside this function.
I have this:
watchers
.ToObservable() // needs to be observable
.SelectMany(watcher => // working on each watcher
Observable
// create a timer for the watcher
.Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
.SelectMany(Observable.FromAsync(
async () => new { watcher, result = await CheckFolder(watcher.Path) })))
.Subscribe(x => Console.WriteLine(string.Format("Watcher: {0}\tResult: {1}\tTime: {2}", x.watcher.Name, x.result, DateTimeOffset.Now))); // tell everyone what happened.
Which is a nice little bit of code from this post that got me started down this road. The goal is to ping a web service (via the CheckFolder() method) every time the Timers publish, based on a given start time and interval.
The trouble is, every time I run the program it outputs a single message for the first Watcher, and then the program exits without error. It gets the first answer, and it's finished.
How do get it to wait for the other publications from all the timers?
I'm almost positive I'm not asking this question the right way, but hopefully a little feedback will help me refine my question.
Thanks.
This is likely because Subscribe is a non-blocking call. I.e. if you have;
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
}
You'll probably find it prints nothing (or maybe "Got 0", depending on how your PC is feeling)
If you stop Main from exiting, by waiting for a key to be pressed, like this:
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
Console.ReadKey();
}
Then it should keep printing out values until you press a key.
The thing to remember is that having an activating subscription, isn't enough to keep your programming running. If you're writing an application with some UI, then you'll usually have a message loop - which will your program alive until you close the window. But that isn't the case for console apps, once you get to the end of main, that's the end of your program.
So you need to find a way to avoid your app exiting before you're reading. Waiting for a specific key to be pressed is a common way to do it, so that may work for you. e.g.
static void Main(string[] args)
{
Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(0.5))
.Subscribe(x => Console.WriteLine("Got " + x));
while (Console.ReadKey().Key != ConsoleKey.Q)
{
}
}