Reactive Extensions - raising async events and subscribing on specific threads - c#

I have a series of modules that use a RX publish/subscribe model.
Here is the event registration code (repeated per subscribing module):
_publisher.GetEvent<DataEvent>()
.Where(sde => sde.SourceName == source.Name)
.ObserveOn(Scheduler.TaskPool)
.Subscribe(module.OnDataEvent);
The publisher is simple, thanks to José Romaniello's code:
public class EventPublisher : IEventPublisher
{
private readonly ConcurrentDictionary<Type, object> _subjects =
new ConcurrentDictionary<Type, object>(); public IObservable<TEvent> GetEvent<TEvent>()
{
var subject = (ISubject<TEvent>)_subjects.GetOrAdd(typeof(TEvent), t => new Subject<TEvent>());
return subject.AsObservable();
}
public void Publish<TEvent>(TEvent sampleEvent)
{
object subject;
if (_subjects.TryGetValue(typeof(TEvent), out subject))
{
((ISubject<TEvent>)subject).OnNext(sampleEvent);
}
}
}
Now my problem: As you can see above I used the .ObserveOn(Scheduler.TaskPool) method to spin off a new thread from the pool for every module, for every event. This is becuase I have lots of events and modules. The problem, of course, is that the events get mixed up in time order, as some events get fired close to each other and then end up calling the OnDataEvent callback in the wrong order (Each OnDataEvent carries a timestamp).
Is there a simple way to use RX to ensure the correct order of events? Or could I write my own Scheduler to ensure each module gets the events in sequence?
The events are published in the correct sequence, of course.
Thanks in advance.

Try using this implementation of the EventPublisher:
public class EventPublisher : IEventPublisher
{
private readonly EventLoopScheduler _scheduler = new EventLoopScheduler();
private readonly Subject<object> _subject = new Subject<object>();
public IObservable<TEvent> GetEvent<TEvent>()
{
return _subject
.Where(o => o is TEvent)
.Select(o => (TEvent)o)
.ObserveOn(_scheduler);
}
public void Publish<TEvent>(TEvent sampleEvent)
{
_subject.OnNext(sampleEvent);
}
}
It uses an EventLoopScheduler to ensure that all events occur in order and on the same background thread.
Remove the ObserveOn from your subscription because if you observe on another thread you risk having events occur in the wrong order again.
Does this solve your problem?

Try the Synchronize method like:
_publisher.GetEvent<DataEvent>()
.Where(sde => sde.SourceName == source.Name)
.ObserveOn(Scheduler.TaskPool).Synchronize()
.Subscribe(module.OnDataEvent);
Although I tried your scenario with same code and found that the data arrive in sequence and doesn't overlap. May be this is something specific to your application.

Related

Is it bad practice for a class to register an event handler for another class?

Should the event subscriber always register the event handler, or is it ok for another class to do it?
Example:
class EventPublisher {
public event EventHandler Event;
}
class EventSubscriber {
public void Handler(object sender, EventArgs e) { }
}
class Glue {
private EventPublisher _publisher = new EventPublisher();
private EventSubscriber _subscriber = new EventSubscriber();
public Glue() {
_publisher.Event += _subscriber.Handler;
}
}
Should the event subscriber always register the event handler, or is
it ok for another class to do it?
There is nothing inherently wrong with this design per se, though it really depends on your architecture and how scaleable and decoupled you want it.
Just a note, there is no context with the generic hypothetical you have put forward with Glue so its hard to tell your exact requirements.
...
These days, i rarely write traditional events and tend to use a more modern approach of Pub/Sub Producer/Consumer Decoupled Messages or an Event Aggregator (depending on the frameworks you are using). Consumers can subscriber at will, and producers can publish at will without any prior knowledge of each other. Martin Follower goes into this pattern in more detail on his site.
More-so, the advantages with Decoupled Messages (and kin), is consumers can subscribe to a conversation without having any previous knowledge of who the producers are, which gives you better decoupling which in turn creates a more maintainable and scalable system. If the system becomes large enough, pushing classes to Microservices can be a lot less painful.
On saying that, if this is only a very simple implementation (and tightly coupled implementation) there is nothing wrong with standard vanilla ice-cream flavored .NET events and having your subscriber register the event handler, though once again you have to break this down into the most logical concern for your design.
I.e should a SoundManager inherently know about a dog and its bark. Or should your dog class register to the sound manager. Your design intuition should lead the way
Anyway, good luck.
Programmatic, it is not wrong and will work smooth for you.
In fact you need to do this in the case where in EventSubscriber of which method
(Handler)should be called on Event , doesn't have object of EventPublisher class.
How to subscribe events is subjective matter, it depends on your over all flow and comfort.
But According to me, subscribing event in side of subscriber class make code more readable and easy to understand
you see to subscribe an event of any class, subscriber class must have an object of that class, but here in your example it doesn't have.
Generally people design architecture in such method when subscriber class itself hold the object of publisher class. This design has its own benefits in some flow, see below example,
public class EventPublisher
{
public event EventHandler HeavyLogicDone;
public void ExposedMethod(string subScriberSpecificData)
{
Thread logicCaller = new Thread(() => HeavyLogic(subScriberSpecificData));
logicCaller.Start();
}
private void HeavyLogic(string subScriberSpecificData)
{
//logic which may take time
if (HeavyLogicDone != null)
HeavyLogicDone(this, new EventArgsClass(subScriberSpecificData));
}
}
here EventPublisher class has a publicly exposed functionality, which should be called by EventSubscriber , but as this method may take time, it is being written in thread.
Now problem, as it is in thread, call of this method will return soon after starting the thread, subscriber can not start its functionality which is dependent on this method's result, it must wait. So to notify subscriber that task has been done, there is an event.
public class EventSubscriber
{
string currentData = "";
public EventSubscriber(EventPublisher eventPublisher, string data)
{
currentData = data;
eventPublisher.HeavyLogicDone += eventPublisher_HeavyLogicDone;
eventPublisher.ExposedMethod(currentData);
//Contineous without waiting for heavy logic to compelete
}
void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
{
if(((EventArgsData)e).subScriberSpecificData == currentData)
{
//Do further task which is dependant to result of logic
//if now subscriber doesn't need to listen this event anymore
((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
}
}
}
As you can seen when to subscribe an event and when to unsubscribe it, subscriber has all control now.
But, if you would be doing like this.
static void Main(string[] args)
{
EventSubscriber subscriber1 = new EventSubscriber("sub1");
EventSubscriber subscriber2 = new EventSubscriber("sub2");
EventPublisher pub = new EventPublisher();
pub.HeavyLogicDone += subscriber1.eventPublisher_HeavyLogicDone;
pub.HeavyLogicDone += subscriber2.eventPublisher_HeavyLogicDone;
pub.ExposedMethod("sub1");
pub.ExposedMethod("sub2");
}
First problem : As you can see, every time you are creating an instance of Subscriber, you have to explicitly write it's subscription and calling of publisher's method for current subscriber. that is coupled code, and you need to keep doing this every time.
and subscriber class
public class EventSubscriber
{
string currentData = "";
public EventSubscriber(string data)
{
currentData = data;
}
public void eventPublisher_HeavyLogicDone(object sender, EventArgs e)
{
if(((EventArgsData)e).subScriberSpecificData == currentData)
{
//Do further task which is dependant to result of logic
//if now subscriber doesn't need to listen this event anymore
((EventPublisher)sender).HeavyLogicDone -= eventPublisher_HeavyLogicDone;
}
}
}
Second problem : as subscription is not in control of subscriber class, and unsubscribing can be done only withing subscriber class. Code will be little mess to understand.

ManualResetEvent WaitOne blocks the owner Thread of my CollectionView

I've written a WPF WizardFramework which performs some actions in the background using some BackgroundWorker. While processing it can happen that I have to update an ObservableCollection which is bound to my UI.
For this case I've written a ThreadableObservableCollection, which provides threadsafe methods for Insert, Remove and RemoveAt. Though I'm using .NET 4.5 I was not able to get BindingOperations.EnableCollectionSynchronization working without many other invalid access exceptions. My Collection looks like:
public class ThreadableObservableCollection<T> : ObservableCollection<T>
{
private readonly Dispatcher _dispatcher;
public ThreadableObservableCollection()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
public void ThreadsafeInsert(int pos, T item, Action callback)
{
if (_dispatcher.CheckAccess())
{
Insert(pos, item);
callback();
}
else
{
_dispatcher.Invoke(() =>
{
Insert(pos, item);
callback();
});
}
}
[..]
}
This is working as expected, while I am using the wizard in my application. Now I'm using NUnit to write some integrationtests for the application.
There's a listener which waits for the WizardViewModel to finish it's work and looking for some pages which are injected in the Steps-Collection. After the asyncrone work is done I can use Validate to check the viewmodel state.
Unfortunately I'm using a ManualResetEvent to wait for the wizard to close. This looks like following:
public class WizardValidator : IValidator, IDisposable
{
private WizardViewModel _dialog;
private readonly ManualResetEvent _dialogClosed = new ManualResetEvent(false);
[..]
public void ListenTo(WizardViewModel dialog)
{
_dialog = dialog;
dialog.RequestClose += (sender, args) => _dialogClosed.Set();
dialog.StepsDefaultView.CurrentChanged += StepsDefaultViewOnCurrentChanged;
_dialogClosed.WaitOne();
}
[..]
}
Now there's a problem:
While the Application is running the UI Thread is not blocked, the Collection can be updated without any problems. But in my testcases the "main" Thread where I initialize the ViewModel (and because of that the Collections) is an AppDomainThread which is blocked by the testcode. Now my ThreadsafeInsert wants to update the collection but cannot use the AppDomain Thread.
But I have to wait for the wizard to finish, how can I solve this kind of deadlock? Or is there a more elegant solution for this one?
edit:
I worked around this problem with a check if there's a user interface, and only then I invoke on the Application-Thread, otherwise I change the collection intentionally on another thread. This does not prevent the exception, but it is not recognized from the test... the items are inserted nevertheless, only the NotifyCollectionChanged-Handler is not called (which is only used in the UI anyway).
if (Application.Current != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
Steps.Insert(pos, step);
stepsView.MoveCurrentTo(step);
});
}
else
{
new Action(() => Steps.Insert(pos, step)).BeginInvoke(ar => stepsView.MoveCurrentToPosition(pos), null);
}
This is an ugly workaround and I am still interested in a clean solution.
Is there a way to use an alternate Dispatcher to create (e.g.) the whole ViewModel and use this to change my collection?
As I see the main problem that main thread is blocked and other operations are trying to be executed in main thread too? What about not to block main thread, like this:
// helper functions
public void DoEvents()
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
public object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
// in your code:
while(!_dialogClosed.WaitOne(200))
DoEvents();
If it will not help then I guess need to try some SynchronisationContext workarounds.
I think the problems boil down to the fact that you create ObservableCollection that is tied to Dispatcher object.
Involving Dispatcher object directly is almost never good idea(as you just witnessed). Instead I would suggest you to see how others have implemented ThreadSafeObservableCollection. This is a little example I put together, it should illustrate the point:
public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
private readonly object _lock = new object();
public ThreadSafeObservableCollection()
{
BindingOperations.CollectionRegistering += CollectionRegistering;
}
protected override void InsertItem(int index, T item)
{
lock (_lock)
{
base.InsertItem(index, item);
}
}
private void CollectionRegistering(object sender, CollectionRegisteringEventArgs e)
{
if (e.Collection == this)
BindingOperations.EnableCollectionSynchronization(this, _lock);
}
}

ExcelAsyncUtil.Observe - to create a running clock in Excel

I am trying out the ExcelAsyncUtil.Observe function. I made the following code that shows a running clock in Excel. It works fine but I am not sure what I am doing. Two questions:
Should I add functionality for observer.OnCompleted() and observer.OnError()? What does these calls do?
What should I do in the IDisposible class? Why is it there?
Here is my sample code:
[ExcelFunction]
public static object MyExcelTicker()
{
return ExcelAsyncUtil.Observe("MyExcelTicker", new object[] { }, TickerFunction());
}
public static ExcelObservableSource TickerFunction()
{
ExcelObservableSource source = new ExcelObservableSource(() => new TickerObservable());
return source;
}
public class TickerObservable : IExcelObservable
{
public IDisposable Subscribe(IExcelObserver observer)
{
var timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += (s, e) => observer.OnNext(DateTime.Now.ToString());
timer.Start();
// What about observer.OnCompleted() and observer.OnError()?
return new TickerDisposable();
}
}
public class TickerDisposable : IDisposable
{
public void Dispose()
{
// What to do here?
}
}
It has been a while and at least one thing is still left not covered, so let me add to what Govert said.
You've asked:
public class TickerDisposable : IDisposable
{
public void Dispose()
{
// What to do here?
}
}
Let's summarize:
For each new subscriber to your clock-ticker, a Subscribe will be called on the TickerObservable. Therefore, for each subscriber, your code will create a new System.Timers.Timer and a new timer.Elapsed event handler - to get your intended effect. And this is actually all that you need to get your effect.
However, you are also required to return an IDisposable, therefore you've created a dummy TickerDisposable solely for that purpose, and you are not sure what it is for.
Answer:
The IDisposable that the library requires you to return from the Subscribe is there just to allow you to cleanup after your glitter stops shining. Timers are a "system thing". Once you create them and start them, they run. After an hour they cannot be GC'ed, because they are meant to be run until you stop them. Surely, you've +='ed an event hander, the observer (if weakly-reference'd) might be already dead, but your timer does not know! You must stop it at some point.
Hence, IDisposable-related pattern, borrowed from RX: whatever heavy or long-living you allocate, reserve, build, etc in the Subscribe method, put some note about it into that (yours!) IDisposable. Then, when the observer unsubscribes, your IDisposable will get cleaned too, and your custom Dispose method will be run, that will be able to look at your IDiposable's contents and .. cleanup the garbage, or rather, unlock it, so the GC can flush them.
Completing your example:
public class TickerObservable : IExcelObservable
{
public IDisposable Subscribe(IExcelObserver observer)
{
var timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += (s, e) => observer.OnNext(DateTime.Now.ToString());
timer.Start();
return new TickerDisposable(timer);
}
}
public class TickerDisposable : IDisposable
{
private Timer ticky;
public TickerDisposable(Timer timer)
{
ticky = timer;
}
public void Dispose()
{
if(ticky != null)
ticky.Dispose(); // or Stop, or etc..
}
}
The above example is actually most-obvious usage of the returned IDisposable. However, you can use it for any register-unregister notification. For example, with single shared timer, it might look like this:
public class TickerObservable : IExcelObservable
{
private static Timer timer = ..... ; // assume it is up & running & shared
public IDisposable Subscribe(IExcelObserver observer)
{
ElapsedEventHander hd = (s, e) => observer.OnNext(DateTime.Now.ToString());
timer.Elapsed += hd;
return new TickerDisposable(timer, hd);
}
}
public class TickerDisposable : IDisposable
{
private Timer ticky;
private ElapsedEventHander handler;
public TickerDisposable(Timer timer, ElapsedEventHander hd)
{
ticky = timer;
handler = hd;
}
public void Dispose()
{
if(ticky != null && handler != null)
ticky.Elapsed -= handler;
}
}
And now you are perfectly sure that no dead-handlers are lingering at the long-living-shared-timer. (of course the cleanup of the timer is missing here, but that's another thing..). Probably you already got the idea, so, have fun!
The IExcelObserver interface matches the semantics of the IObserver interface from the Reactive Extensions library (http://msdn.microsoft.com/en-us/library/dd783449.aspx).
You function can call OnNext zero or more times, and then call OnError if an error occurs, or OnCompleted if no further events will be raised. Excel-DNA will handle OnError as it would an exception thrown by a regular UDF, and will return #VALUE to the cell or process the exception via the registered UnhandledExceptionHandler. OnCompleted is not so useful in the Excel context - it just indicates that no further values will be raised.
For your example, error don't seem to be a problem, and there is no end to the stream of events, so you need never call OnError or OnCompleted.
The Excel-DNA infrastructure will call the IDisposable.Dispose when the observable is no longer hooked up to a cell formula. For example, if the formula with the MyExcelTicker() call is deleted from the cell. You can use this as a notification to clean up any back-end resources, or ignore the notification if you're not interested.

Subscribing to EF changes with RX

I'm probably totally misunderstanding what RX is all about, but I thought it would be a neat way of allowing various client applications in my code to subscribe to notifications of changes to certain Entity Framework Code First types.
So in my UOW Commit methood I have
var changes = DbContext.ChangeTracker.Entries<EntEvent>().Where(ee => ee.State != EntityState.Unchanged);
Hub.Instance.NotifyBeforeSave(changes);
and my (rather basic) hub class looks like this...
public sealed class Hub
{
private static readonly Hub instance = new Hub();
static Hub(){}
private Hub(){}
public static Hub Instance
{
get { return instance; }
}
public IObservable<System.Data.Entity.Infrastructure.DbEntityEntry<EntEvent>> BeforeSave = new Subject<DbEntityEntry<EntEvent>>();
public void NotifyBeforeSave<T>(IEnumerable<System.Data.Entity.Infrastructure.DbEntityEntry<T>> changes) where T:class
{
var x = changes.Where(c => typeof(T) == typeof(EntEvent)) as IEnumerable<System.Data.Entity.Infrastructure.DbEntityEntry<EntEvent>>;
BeforeSave = x.ToObservable();
}
}
and then I thought I could subscribe a client (observer) by creating an instance of the following and calling attach.
public class SampleConsumer : IObserver<DbEntityEntry<EntEvent>>
{
public void attach()
{
Hub.Instance.BeforeSave.Subscribe(this);
}
public void OnNext(DbEntityEntry<EntEvent> value)
{
var x = value;
}
public void OnError(Exception error)
{
var y = error;
}
public void OnCompleted()
{
}
}
but breakpoints in OnNext and OnError never get called.
I'm probably 180deg away from where I should be, but we have to start somewhere!
The problem is that you don't have an asynchronous source.
DbContext.ChangeTracker.Entries<EntEvent>()
is a collection. You can convert it to an observable using
IEnumerble.ToObservable();
but that does not make it asynchronous. In fact, it will enumerate the collection right away upon subscription. If the collection happens to be empty, it will do nothing at all. Google the difference between cold/hot observables to understand.
You need an asynchronous source, something like an event.
I don't know EF very well, my guess is that the
((IObjectContextAdapter)DbContext).ObjectContext.SavingChanges
event might be what you need.
Good luck!
Plug in Nick's
https://github.com/NickStrupat/EntityFramework.Triggers
https://github.com/NickStrupat/EntityFramework.Rx
He has patterns with and without deriving from his context, that permit:
DbObservable<Context>.FromInserted<Person>();

Horrible "Callback chains" in winforms application

I'm working on a winforms application that is very complicated, and has massive callback chains being passed around all over the place.
As an example loosely based on this code, there could be a "Manager" class, that spawns a class "SetUpWorkerThreads" class, which creates a "HandleWorker" thread for say 10 workers.
The worker thread needs to call back to the manager class on occasion, to achieve this the code looks like this:
public class Manager
{
public delegate void SomethingHappenedHandler();
private void Init()
{
var x = new SetUpWorkerThreads(SomethingHappened);
}
private void SomethingHappened()
{
// Handle something happened
}
}
public class SetUpWorkerThreads
{
private readonly Manager.SomethingHappenedHandler _somethingHappened;
public SetUpWorkerThreads(Manager.SomethingHappenedHandler somethingHappened)
{
_somethingHappened = somethingHappened;
}
public void SetupTheThreads()
{
// Contrived!
for (int x=0; x<10; x++)
{
var worker = new Worker(_somethingHappened);
new Thread(worker.DoingSomething).Start();
}
}
}
public class Worker
{
private readonly Manager.SomethingHappenedHandler _somethingHappened;
public Worker(Manager.SomethingHappenedHandler somethingHappened)
{
_somethingHappened = somethingHappened;
}
public void DoingSomething()
{
// ... Do Something
_somethingHappened();
}
}
In reality, there can be many more classes involved, each passing around a mass of callbacks for various things. I realise that poor class/application design is playing a part in this, but are there better ways to go about handling these interactions between classes, specifically in winforms apps, and when a lot of threading is going on?
I can't see that the threading makes it more or less problematic.
One alternative is to use events instead of callbacks, but that won't break up the long chains and will give you an unsubscribing hell too.
One possible approach is to create an object responsible for handling all the events. Either as a singleton or as a single object that you pass to all your threads (instead of the callbacks). Then you can have a simple interface on the EventRouter object to raise events from the threads. You can then subscribe to events on the EventRouter where you need to handle "something happened".
Edit
Something the GoF pattern Mediator but with a publisher-subscriber twist.

Categories

Resources