Rx .net Subscribe() and EventPattern oddity - c#

I'm using Rx in conjunction with a third-party API that uses the EventPattern. In this API you register your event handlers on the object and then invoke a method, StartWatching(), on the object that starts the events to begin triggering. I am using Observable.FromEventPattern to bridge the API in the Rx world but I am running into very odd problems where subscriptions will only work if they are called right by the invocation of StartWatching(). Below is a reduced case of what I am seeing.
This works:
foreach (var iq in interactionQueues)
{
Observable.FromEventPattern(iq, "TheEvent")
.Subscribe(e => Log.Info("I got called!"),
e => Log.Info("Error!", e),
() => Console.WriteLine("Seq completed!"));
iq.StartWatching();
}
If I call the Subscribe() and StartWatching() in different loops it stops working:
foreach (var iq in interactionQueues)
Observable.FromEventPattern(iq, "TheEvent")
.Subscribe(e => Log.Info("I got called!"),
e => Log.Info("Error!", e),
() => Console.WriteLine("Seq completed!"));
foreach (var iq in interactionQueues)
iq.StartWatching();
My only thought as to why this may happen is that the Observing or Subscribing is happening on the wrong thread. I have tried using Scheduler.CurrentThread and Scheduler.Immediate with SubscribeOn and ObserveOn but that didn't help. Any other ideas? Should I try a different Scheduler or is that a red herring?

Let's wrap this in a more friendly method:
public static TheEventArgs WatchEvent(this InteractionQueue this)
{
var ret = Observable.Create<TheEventArgs>(subj => {
// This entire block gets called every time someone calls Subscribe
var disp = new CompositeDisposable();
// Subscribe to the event
disp.Add(Observable.FromEventPattern(iq, "TheEvent").Subscribe(subj));
// Stop watching when we're done
disp.Add(Disposable.Create(() => iq.StopWatching());
iq.StartWatching();
// This is what to Dispose on Unsubscribe
return disp;
});
// When > 1 person Subscribes, only call the block above (i.e. StartWatching) once
return ret.Multicast(new Subject<TheEventArgs>()).RefCount();
}

Related

Correctly subscribing to the current observable when using switch on observable stream

I have encountered something strange when using System.Reactive. Maybe this is the regular behavior but makes little sense to me.
Let's take following code:
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> I = Observable.Interval(TimeSpan.FromSeconds(1));
async Task Main()
{
X.Switch().Subscribe(x => Console.WriteLine($"switched_1: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_1: {x}"));
X.Switch().Subscribe(x => Console.WriteLine($"switched_2: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_2: {x}"));
await Task.Factory.StartNew(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false);
X.Switch().Subscribe(x => Console.WriteLine($"switched_3 !!!: {x}"));
I.Subscribe(x => Console.WriteLine($"direct_3: {x}"));
});
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.ReadLine();
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.WriteLine("New observable emited");
Console.ReadLine();
}
The observable marked with !!! is never hit until the second Interval is emitted.
[Update]
I think I know what's happening: I am subscribing to the upstream observable each time with a new switch. And while I am doing this, I will get notified only about the observable emitted after the subscription, and I can not "connect" to the current observable.
I thought that by using switch only once, and subscribe to the resulting observable later will help:
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> XI;
void Main()
{
XI = X.Switch().AsObservable();
XI.Subscribe(x => Console.WriteLine($"switched_1: {x}"));
XI.Subscribe(x => Console.WriteLine($"switched_2: {x}"));
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
XI.Subscribe(x => Console.WriteLine($"switched_3 !!!: {x}"));
Console.ReadLine();
X.OnNext(Observable.Interval(TimeSpan.FromSeconds(1)));
Console.WriteLine("New observable emited");
Console.ReadLine();
}
But did not :(
[Update 2]
It seems that I have found a solution that actually works, but I am not sure if it is correctly used or not.
Subject<IObservable<long>> X = new Subject<IObservable<long>>();
IObservable<long> XI;
async Task Main()
{
XI = X.Switch().Publish().AutoConnect();
...
How can I make it work form the very beginning?
Your explanation under [Update] is correct because Task.Factory.StartNew is returning a Task<Task> instead of a Task. You have to use a double await or Task.Run if you want that the subscription happens before you call OnNext().
However only exposing a XI-Observable as in [Update2] and hide the fact that there is something switched underneath is a viable option.
With Publish().AutoConnect() you transform the observable from cold to hot. You can also try out a BehaviorSubject or a ReplaySubject on your snippet to understand the differences between hot & cold. If you understand these differences it should be much clearer for you, how the actual solution you have in mind has to look like.

Observable (and cancelable) loop

I'm creating an emulator. The core of the emulation runs in an infinite loop like this:
while (true)
{
UpdateMachineState();
}
I would like to introduce Reactive Extensions to execute this loop into another thread and to make it cancelable, but I'm completely lost.
Since my emulator is a GUI application (Universal Windows), I don't wan't to block the UI thread.
It should look like:
...
while (true)
{
if (machine.IsHalted)
{
observer.OnCompleted;
}
observer.OnNext(machine.GetState());
cancellationToken.ThrowIfCancellationRequested();
}
...
The created sequence would eventually complete when the emulator enters the "halted" state. Otherwise, it will keep pushing States (an object that represents its internal state) forever.
I've tried with Observable.Create, but the overload that provides a CancellationToken requires a Task<Action>.
Here's how you do it in Rx:
void Main()
{
var scheduler = new EventLoopScheduler();
var loop = scheduler.Schedule(a =>
{
UpdateMachineState();
a();
});
Thread.Sleep(1);
loop.Dispose();
}
public void UpdateMachineState()
{
Console.Write(".");
}
The overload on .Schedule that I used takes a Action<Action> as the parameter. You simply call the inner action if you want the the action to be rescheduled - so the above code effectively creates the infinite loop.
You then call .Dispose() on the return from the .Schedule call to cancel the loop.
Another alternative is to use the .Generate operator:
var scheduler = new EventLoopScheduler();
var query =
Observable
.Generate(0, x => true, x => x, x => machine.GetState(), scheduler);
var subscription = query.Subscribe(x => Console.Write("."));
Thread.Sleep(1);
subscription.Dispose();

Observable.Using( ) cancellation

I have a observable made by the Using helper:
var o = Observable.Using(
() => {
return new MyResource
},
res => {
return new Observable.Create<string>(observer => ....);
});
How can I cancel the observable? And by that make sure MyResource is disposed of?
I see there are a Observable.Using( ) that includes a cancellationToken, but signature is so different, that I'm not able to make it work...
Update:
As James points out, by disposing the observable, my resource will be disposed as well. In my case, a plain disposal is not enough. I need to call a method on the resource first. How can that be archived?
You don't need to clean up an observable - just the subscription. Simply call Dispose on the handle returned from Subscribe when you make a subscription to cancel it.
The resource created by the factory delegate supplied as the first argument to Using has a lifetime governed by lifetime of subscriptions to the observable created by Using.
Here's an example:
var xs = Observable.Using(
() => {
var resource = Disposable.Create(() => Console.WriteLine("Binned"));
Console.WriteLine("Created");
return resource;
},
res => Observable.Never<Unit>());
Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();
var sub2 = xs.Subscribe();
Console.WriteLine("Disposing");
sub1.Dispose();
Gives output:
Subscribing
Created
Created
Disposing
Binned
Since sub2 never finishes and isn't disposed, there is only a single Binned message displayed.
In this example, sub1 completes immediately and there is no cancellation:
var xs = Observable.Using(
() => {
var resource = Disposable.Create(() => Console.WriteLine("Binned"));
Console.WriteLine("Created");
return resource;
},
res => Observable.Return(1));
Console.WriteLine("Subscribing");
var sub1 = xs.Subscribe();
This time the resource is still cleaned up, because the subscription terminated normally:
Subscribing
Created
Binned
The purpose of the overload of Using sporting cancellation tokens is to allow you to cancel asynchronous creation of the resource and the dependent observable. The cancellation tokens are signalled on disposal of subscription handles - of course this scenario is only really going to be useful if you have relatively lengthy creation times and early disposal is likely.
Addendum
To address the corollary to your question:
...a plain disposal is not enough. I need to call a method on the resource first. How can that be [achieved]?
From your resource factory method (the first argument to using), do this:
var xs = Observable.Using(
() =>
{
var processHandle = /* code to create process */
return Disposable.Create(() => /* code to kill process using processHandle */;
},
// Rest of code...
Disposable.Create is a helper method you can use that accepts in Action that's invoked upon disposal.

How to set dispose action to Observable?

I know how to create an observable and assign a disposing action:
Observable.Create(o =>
{
// o.OnNext etc.
return Disposable.Create(() => { /* ... */ });
});
But now I produced an observable from query syntax:
var observable = from x in otherObservable
select x;
How to assign a disposing action to such query?
If I understand correctly, you want to "chain" or "listen" whenever the subscription is disposed. One way to do this is to use the Finally operator of IObservable<T>, as such:
var ob = from x in Observable.Interval(TimeSpan.FromSeconds(1))
select x;
// Use Finally to create an intermediate IObservable
var disposeSub = ob.Finally(() => Console.WriteLine("disposed"));
// Subscribe to the intermediate observable instead the original one
var yourSub = disposeSub.Subscribe(Console.WriteLine);
// Wait for some numbers to print
Thread.Sleep(TimeSpan.FromSeconds(4));
// "disposed" will be written on the console at this point
yourSub.Dispose();
Hope that helps!
I think you should clarify your question. It's not entirely clear what you mean by "disposing action".
Calling an action using Observable.Finally has been suggested, but this action would run when the first of the following conditions is met:
The Observable sends OnCompleted()
The Observable sends OnError()
The subscription handle is disposed.
i.e. You can't guarantee that the action will be executed precisely when you call Dispose on the subscription handle; it may have already been run - but calling Dispose ensures it will have been invoked before the call to Dispose returns.
This may be what you need - but taking you at your word, you only want the action to run in the last of these cases - on dispose of the handle, then you would need to attach the action to the subscription handle itself, ie:
var otherDisposable = /* your observable */;
Action disposingAction = () => Console.WriteLine("I am disposed!");
var subscription = otherDisposable.Subscribe(/* set your handlers here */);
var disposable = new CompositeDisposable(
subscription,
Disposable.Create(disposingAction));
/* The disposingAction is *only* run when this is called */
disposable.Dispose();
I can't think what scenario would require this though, I wonder if Observable.Finally, as suggested by Carlos, is a better fit!
You don't dispose an observable. You dispose a subscription to an observable.
Example:
var observable = from x in otherObservable
select x;
var sub = observable.Subscribe(DoStuff);
sub.Dispose();

Using Rx to synchronize asynchronous events

I want to put Reactive Extensions for .NET (Rx) to good use and would like to get some input on doing some basic tasks. To illustrate what I'm trying to do I have a contrived example where I have an external component with asyncronous events:
class Component {
public void BeginStart() { ... }
public event EventHandler Started;
}
The component is started by calling BeginStart(). This method returns immediately, and later, when the component has completed startup, the Started event fires.
I want to create a synchronous start method by wrapping the component and wait until the Started event is fired. This is what I've come up with so far:
class ComponentWrapper {
readonly Component component = new Component();
void StartComponent() {
var componentStarted =
Observable.FromEvent<EventArgs>(this.component, "Started");
using (var startedEvent = new ManualResetEvent(false))
using (componentStarted.Take(1).Subscribe(e => { startedEvent.Set(); })) {
this.componenet.BeginStart();
startedEvent.WaitOne();
}
}
}
I would like to get rid of the ManualResetEvent, and I expect that Rx has a solution. But how?
PL's answer if perfectly good for your spec, but I thought you might get better results by not fighting RX with .First() but embracing it with creating an observable to your component:
public static IObservable<Unit> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return Observable
.FromEvent<EventArgs>(component, "Started")
.Select(_ => new Unit());
});
}
Then you could use it as blocking:
new Component().AsObservable().First();
Non - blocking:
new Component().AsObservable().Subscribe(_ => Console.WriteLine("Done"));
Hot:
var pub = new Component().AsObservable().Publish();
pub.Subscribe(_ => Console.WriteLine("Sub1"));
pub.Subscribe(_ => Console.WriteLine("Sub2"));
pub.Connect(); // started just once per two subscriptions
Composable:
new Component().AsObservable().Delay(TimeSpan.FromSeconds(1));
etc...
EDIT: For the case of multiple events that you have to wait on and collect information,
the following variation could be used:
public static IObservable<EventArgs> AsObservable(this Component component)
{
return Observable.Defer(() =>
{
component.BeginStart();
return
Observable.FromEvent<EventArgs>(component, "Started1").Take(1)
.Merge(
Observable.FromEvent<EventArgs>(component, "Started2").Take(1))
.Select(evt => evt.EventArgs);
});
}
With this one, if you want to block till completion, you might use .AsObservable.Last().
Something like this should do it:
var replay = Observable
.FromEvent<EventArgs>(this.component, "Started")
.Replay();
replay.Connect();
component.BeginStart();
replay.First();

Categories