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.
Related
I have been crawling around on Google a bit now to find any useful examples on how to use Ninject together async/await operations. I have also tried a bit myself to find any pattern that makes this actually work without having to write a lot of code, but I haven't managed to make it work.
To take the most simple description of the basic problem is that the Entity Framework DbContext is created on a per request scope basis (it's an ASP.NET MVC app), but if you try to call any *Async methods it will fail with information that it's already working with an execution (which is obvious enough).
So, what I need is that the call Kernel.Get<MyContext>() creates unique DbContext objects using Ninject and which Ninject takes care of the lifecycle of. Using BeginBlock() or changing scope to InTransientScope() isn't really an option since the first will make the code quite heavy with seperate blocks and disposing of these and the latter set's the caller code as responsible to dispose the DbContext.
An POC example of the code I want to do:
var context1 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var context2 = NinjectKernelReference.Get<MyContext>(); //I want this to be a unique reference
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
So, is there any way to solve this the "easy" way?
this is how you can control creation of objects yourself:
public interface IContextFactory {
MyContext Create();
}
kernel.Bind<IContextFactory>().ToFactory // requires ninjext.extensions.factory
(Factory Extension Link)
usage:
using(var context1 = IContextFactory.Create())
using(var context2 = IContextFactory.Create())
{
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
} // context get's disposed here
note: this requires the context not be bound .InRequestScope(), otherwise, the same object will be returned for both .Create()calls.
If you sometimes need them .InRequestScope() and sometimes not, you might consider using ninject contextual binding
After some digging and reading the response of other users on this post, I realize that it isn't any easy way to do this.
So I decided to go for using the IKernel.BeginBlock to create a "local" Ninject scope within the Parallel thread execution where I did my logic.
It may not be so neat as I would like, but it works.
using( var block1 = NinjectKernelReference.BeginBlock())
using( var block2 = NinjectKernelReference.BeginBlock())
{
var context1 = block1.Get<MyContext>();
var context2 = block2.Get<MyContext>();
var task1 = context1.Customers.Where(c => c.ZipCode == "4444")
.Select(c => new {
c.Name,
c.PhoneNumber
})
.Take(50)
.ToArrayAsync();
var task2 = context2.Customers.CountAsync(c => c.ZipCode == "4444");
Task.WaitAll(task1, task2);
return new Result { task1.Result, task2.Result };
}
It may not be that neat, but it works and I can't see any downsides with this (other than maybe some minor performance issues with BeginBlock and Disposing of it).
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();
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();
}
I have a token for various tasks and I need to better manage their cancellation, to be notified of a cancellation I can use:
token.Register(RegisterMethod);
How can I remove this "subscription"?
Is there any way to "UnRegister"?
I thought about doing a workaround with TaskCompletionSource. But I do not know if it would work well. What is the best way to solve this approach?
CancellationToken.Register returns a CancellationTokenRegistration instance. If you call Dispose on that instance, your registration will be removed.
You can safely dispose the entire CancellationTokenSource. Without worry about unregister callbacks.
Code:
https://github.com/microsoft/referencesource/blob/master/mscorlib/system/threading/CancellationTokenSource.cs#L552
The Dispose() method of the CancellationTokenSource will call dispose on every registered callback you added into your Token via Token.Register(callBack).
There is no way to really undo a registration.
While the dispose method will remove the callback the token still contains the information that there is a registration:
var cancellationTokenSource = new CancellationTokenSource();
basicTask = Task.Factory.StartNew(() => {
for (;;) {
var z = DateTime.Today.ToString();
}
}, cancellationTokenSource.Token);
var basicTask2 = Task.Factory.StartNew(() => {
for (;;) {
var z = DateTime.Today.ToString();
}
}, cancellationTokenSource.Token);
//var usingThisCodeWillResultInADeadlock = cancellationTokenSource.Token.Register(() => { });
//usingThisCodeWillResultInADeadlock.Dispose();
cancellationTokenSource.Cancel();
basicTask.Wait();
Disabling the comments will result in a deadlock.
Taking my first steps with Rx I am stuck here:
public class DisposableResourceDemo : IDisposable
{
public DisposableResourceDemo() {
Console.WriteLine("DisposableResourceDemo constructor.");
}
public void Dispose() {
Console.WriteLine("DisposableResourceDemo.Dispose()");
}
public void SideEffect() {
Console.WriteLine("DisposableResourceDemo.SideEffect()");
}
}
[Test]
public void ShowBehaviourOfRxUsing()
{
var test = Observable.Using(() =>
{
// This should happen exactly once, independent of number of subscriptions,
// object should be disposed on last subscription disposal or OnCompleted call
return new DisposableResourceDemo();
},
(dr) =>
{
return Observable.Create<string>(
(IObserver<string> observer) =>
{
dr.SideEffect();
var dummySource = Observable.Return<string>("Some Text");
return dummySource.Subscribe(observer);
});
}).Publish().RefCount();
Console.WriteLine("before 1st subscription.");
test.Subscribe(Console.WriteLine, () => Console.WriteLine("OnCompleted in 1st."));
Console.WriteLine("before 2nd subscription.");
test.Subscribe(Console.WriteLine, () => Console.WriteLine("OnCompleted in 2nd."));
}
To my surprise the code above yields
before 1st subscription.
DisposableResourceDemo constructor.
DisposableResourceDemo.SideEffect()
Some Text
OnCompleted in 1st.
DisposableResourceDemo.Dispose()
before 2nd subscription.
--> [happy with missing "Some Text" here]
OnCompleted in 2nd.
--> [unhappy with second instantiation here]
DisposableResourceDemo constructor.
DisposableResourceDemo.SideEffect()
DisposableResourceDemo.Dispose()
Please note that calling Connect() manually after both subscriptions is not what I want here, though then the output is as expected.
I am not totally sure what you are trying to achieve here. It seems that you want to share the observable sequence and its related resources. So the standard ways to do this is with the ConnectableObservable types that you get from .Replay() and .Publish() etc
You say you dont want to use .Connect() and instead you use .RefCount() which is very common. However, your sequence completes. You also are using the Extension method Subscribe(...) which will internally create an Auto detaching observer, i.e. when the sequence completes, it will disconnect.
So my question is, should the internal sequence actually complete?
If the answer is yes, then why would the 2nd subscription get the OnComplete notification...it has happened already, it is in the past. Maybe you do want to replay the OnComplete, in which case maybe .Replay(1) is what you want.
If the answer is no, then you can easily fix this by putting a Concat(Observable.Never<string>()) either before the .Publish() or after the Observable.Return.