How to send a message in event handler in akka.net? - c#

I have an actor that has a custom timer that fires events in non real-time intervals. (This is why I cannot use scheduler)
In event handler I want to send a message to self or another actor. I am receiving an NotSupportedException.
I have a custom time source similliar to the NodaTime FakeClock class.
public class NodaTimeControllableClock
{
public void AddInterval(Duration interval);
public Instant Now { get; protected set; }
public event EventHandler<TimeChangedEventArgs<Duration>> TimeChanged;
}
It is used in timer class to trigger events every specified amount of time.
public class NodaTimer
{
Duration Interval { get; set; }
void Start();
void Stop();
bool IsRunning { get; private set; }
event EventHandler<TimerTickedEventArgs> TimerTicked;
}
Now, I create a timer instance for some of my actors and store it inside them.
protected override void PreStart()
{
base.PreStart();
timer.Interval = Duration.FromSeconds(1);
timer.TimerTicked += Timer_TimerTicked;
timer.Start();
}
private void Timer_TimerTicked(object sender, TimerTickedEventArgs e)
{
Self.Tell(new SomeMessage());
//Here I want to send the message to the parent or
//if it's impossible to do so I could queue some message
//to the Self messagebox.
}
What is the pattern to work with sending messages on events? Is there any?

Probably the source of your issues is Self member call made inside Timer_TimerTicked. Reason for this is that Self just like Context is a computed property, that is available only within currently executing actor's thread. If you call it from the outside (another thread like in the case of timer callbacks), it may be not initialized.
Weak solution is just to store reference to Self in some other field, and use that field to send message instead.
Better solution in your case is to use built-in Akka.NET Scheduler, which offers ability to perform actions or make calls in specified time intervals:
class MyActor : ReceiveActor
{
private readonly ICancelable cancelTimer;
public MyActor()
{
var interval = TimeSpan.FromSeconds(1);
cancelTimer = Context.System.Scheduler
.ScheduleTellRepeatedlyCancelable(interval, interval, Self, new SomeMessage(), ActorRefs.NoSender);
}
protected override void PostStop()
{
cancelTimer.Cancel();
base.PostStop();
}
}

Related

Listen for event and invoke callback, based on specification?

I am currently building out a custom task manager and I'm wondering if it's possible to tell the task manager to listen for a specific event (OnSomething below), and then invoke a callback method when the task raises that event. However, mentally I can't see how it's possible to listen for an event that doesn't exist at the base class level. For example, I have a base class that contains basic information about the task called CustomTask:
public abstract class CustomTask {
public bool IsRunning { get; private set; } = false;
public void Start() {
IsRunning = true;
DoSomething();
IsRunning = false;
}
protected abstract void DoSomething();
}
For the sake of SO readers, I've simplified the definition, but you get the gist of it. It contains basic details, a few methods for starting and canceling, provides basic state management (simplified IsRunning here), etc.
I then have custom tasks that derive from CustomTask, in this case, let's focus on a sample task called CustomTaskA. It contains a definition for an event called OnSomething, which someone, somewhere may want to listen for:
public sealed class CustomTaskA : CustomTask {
protected override void DoSomething() => RaiseOnSomething(this, new EventArgs());
public event EventHandler<EventArgs> OnSomething;
private void RaiseOnSomething(object sender, EventArgs e) => OnSomething?.Invoke(sender, e);
}
Now, the CustomTaskManager registers tasks, tracks them via Guid, manages them and more, but for simplicity:
public sealed class CustomTaskManager {
// Singleton setup.
private static CustomTaskManager _instance = new CustomTaskManager();
public static CustomTaskManager Instance {
get {
// Simplified for SO.
if (_instance == null)
_instance = new CustomTaskManager();
return;
}
}
// Collection of tasks.
private Dictionary<Guid, CustomTask> _tasks = new Dictionary<Guid, CustomTask>();
// Register and start a task.
public bool TryRegisterAndStartTask(CustomTask task, out Guid taskId) {
taskId = Guid.Empty;
try {
// Register task.
taskId = Guid.NewGuid();
_tasks.Add(taskId, task);
// Listen for events.
// Start task.
task.Start();
} catch (Exception e) {
// Log exception.
}
return false;
}
}
When registering and starting a task, I'd like to tell the task manager I want to listen for OnSomething, and if OnSomething is invoked, I want the task manager to call a method OnSomethingWasRaised. For example:
TaskManager.Instance.TryRegisterAndStartTask(task, out Guid taskId, task.OnSomething, OnSomethingWasRaised);
private static void OnSomethingWasRaised(object sender, EventArgs e) {
Console.WriteLine("Woohoo!");
}
I know the specifying and invoking a callback method is entirely possible, and listening for events is plausible with reflection.
Is there a way (with or without using reflection) to listen for a specified event defined on a derived object and then invoke a specified callback method?
NOTE: Please excuse any syntactical errors as I hand-typed the snippets to keep them minimal.
Problem with (proposed) approach like this:
TryRegisterAndStartTask(task, out Guid taskId, task.OnSomething, OnSomethingWasRaised);
is that you cannot pass event as argument, or store it in variable, because event is just a set of two methods (add and remove), just like property is a set of two methods get and set.
You can of course change event to "raw" delegate:
public EventHandler<EventArgs> OnSomething;
This one you can pass by reference:
public bool TryRegisterAndStartTask(CustomTask task, ref EventHandler<EventArgs> del, EventHandler<EventArgs> sub, out Guid taskId) {
taskId = Guid.Empty;
// subscribe
del += sub;
...
}
CustomTaskManager.Instance.TryRegisterAndStartTask(task, ref task.OnSomething, OnSomethingWasRaised, out var taskId);
But that's usually not a good idea, since you are losing private scope of events - with events one can only add\remove delegates, with raw delegate anyone can do anything, like invoking or setting to null.
If regular event stays - that means reflection is the only way to achieve your goal, and even worse - you'll have to reference to the event you want to subscribe to by string name, not by an actual reference, though you can use nameof(task.OnSomething). Then, you are losing compile time validation of subscription delegate type. Say you want to subscribe to event Action Something but passing Func<string> delegate there. It will compile fine with reflection approach, and fail only at runtime.
Still if you insist that will look something like this:
public bool TryRegisterAndStartTask(CustomTask task, string eventName, Delegate sub, out Guid taskId) {
taskId = Guid.Empty;
// subscribe
var ev = task.GetType().GetEvent(eventName, BindingFlags.Public | BindingFlags.Instance);
var addMethod = ev.GetAddMethod(); // this can be null or private by the way
addMethod.Invoke(task, new [] {sub});
...
}
And called like this:
var task = new CustomTaskA();
EventHandler<EventArgs> handler = OnSomethingWasRaised;
CustomTaskManager.Instance.TryRegisterAndStartTask(task, nameof(task.OnSomething), handler, out var taskId);
Ugly, unsafe, and not worth it in your scenario, in my opinion.

How to dispatch work among several processors?

I have a class wich performs some data processing:
class Processor
{
public Processor() {
// Load lot of data
}
public string GetResult(string input) {
// ...
}
}
I need to implement a service wich exposes HTTP API to this class. I use Owin and Microsoft.AspNet.* libs to host HTTP Web API. For each request it creates a new thread to handle it, but I cannot instantiate Processor on every request as it takes enormous time to load some data in its constructor. Also I cannot reuse one instance from different threads as it was not designed to be thread safe. But I can instantiate several instances of Processor on service start, and then dispatch work among them. Say I allow up to 20 concurrent HTTP requests for my service. I create 20 instances of Processor and add Busy flag to the class:
class Processor
{
public bool Busy { get; set; }
// ...
}
I wrote Dispatcher class like this:
class Dispatcher
{
readonly Processor[] _processors;
readonly SemaphoreSlim _semaphore;
public Dispatcher(int maxProcessors)
{
_semaphore = new SemaphoreSlim(maxProcessors);
_processors = new Processor[maxProcessors];
// Instantiate Processors, etc...
}
public string GetResult(string input)
{
try
{
_semaphore.Wait(); // Surplus requests will wait here.
Processor processor;
lock (_processors)
{
// It is guaranteed that such processor exists if we entered the semaphore.
processor = _processors.First(p => !p.Busy);
processor.Busy = true;
}
var result = processor.GetResult(input);
processor.Busy = false;
return result;
}
finally
{
_semaphore.Release();
}
}
}
Then I can basically call it through Dispatcher in ApiController:
public class ServiceController : ApiController
{
static Dispatcher _dispatcher = new Dispatcher(20);
[Route("result")]
[HttpGet]
public string Result(string input)
{
return _dispatcher.GetResult(input);
}
}
Is it implemented correctly for my purpose?
I tested it and it works, but I wonder if I reinvented the wheel and .NET Framework has somewhat ready to use for my case, or if it could be implemented easier.
Basically in your class that is going to be run in the thread, create an event and event handler. The object that then spins up this task can register to that event. When it is raised by the task, (in this case you would raise the event when it is done) you can do something, ie. give it more work.
Create your events in the class that will be run in the child thread:
public event TaskCompleteEventHandler OnComplete;
public event TaskErrorEventHandler OnError;
Register to your events in the object that is spinning up the classes:
task.OnComplete += TaskComplete;
task.OnError += TaskComplete;
Create the function in the calling class that will handle the event:
public void TaskComplete()
{
//give the thread more work
}

Callback-way to work with Events

I do not understand some things of work with callbacks.
I have some third-party code wich connect,disconnect,subscribe to values from some system.
So, the example is:
class Subscriber:ISubscriber
{
public void OnConnected()
{
}
public void OnDisconnected()
{
}
}
Then, it uses:
var subscriber=new Subscriber();
_someSystemObj.CreateConnection(subscriber); //i do not understand how it works there
And then _someSystemObj calls OnConnected or OnDisconnected.
So, i have two questions:
1.How can _someSystemObj calls OnConnected method (it use Observer pattern or may be it use it other way. Can you describe it? Get some schematic code to understand how it may work.
If i want to do many steps when OnDisconnect happens: should i throw some public event to other classes? I mean than i can not do Disconnection in this OnDisconnect method (i have to do some steps in other part of my code and at old version of this API i just rethrow event OnDisconnect on top of my program and then handle it.)
This old version of code looks like:
_server.OnDisconnect+=OnDisconnectHandler;
void OnDisconnectHandler(..)
{
if(OnReconnect!=null)//some public event
OnReconnect(e);// throw on top of my program and then handle it there
}
At new version of API i try to solve it by add public event and when OnDisconnect happens throw it on top:
class Subscriber:ISubscriber
{
public event EventHandler<EventArgs> OnDisconnectedHappens;
public void OnConnected()
{
}
public void OnDisconnected()
{
if(OnDisconnectedHappens!=null)
OnDisconnectedHappens(this,e);//thow on top
}
}
And in some place:
_subscriber.OnDisconnectHappens+=OnDisconnectHandler; //and do my work
Or, may be it not right way. May be i should do something else?
Please,can you give me a some link, that i can learn about this model of event callbacks?
Or, may be i do it correctly?
How can _someSystemObj call OnConnected method?
Well, you gave it a subscriber when you called CreateConnection(subscriber). It's probably implemented something like this:
private readonly List<ISubscriber> _subscribers = new List<ISubscriber>();
public void CreateConnection(ISubscriber subscriber)
{
_subscribers.Add(subscriber);
}
private void OnConnectedNotifySubscribers()
{
foreach (ISubscriber subscriber in _subscribers)
{
subscriber.OnConnected();
}
}
If I want to do many steps when OnDisconnect happens, should I raise some public event to other classes?
That is a valid option, but it can get difficult to debug when there are too many layers in an event chain. Another option is to increase the capability of your Subscriber class so that it can do everything necessary to handle the subscription events.
class EmpoweredSubscriber : ISubscriber
{
private readonly DisconnectWorker _worker;
private readonly DisconnectHelper _helper;
public EmpoweredSubscriber(DisconnectWorker worker, DisconnectHelper helper)
{
_worker = worker;
_helper = helper;
}
public void OnConnected()
{
}
public void OnDisconnected()
{
_worker.DoWork();
_helper.DoHelp();
// more...
}
}

event priority and process order

Is there a way to specify an order or priority to handle registered event delegates? For example, I have an event that I would like processed immediately before any other events, but I want other objects to be allowed to register listeners to the event as well. How can this be accomplished?
Lets say I want proc1 to always run before proc 2.
class MessageProcessor
{
private DataClient Client;
public MessageProcesser(DataClient dc)
{
Client = dc;
Client.MessageReceived += ProcessMessage;
}
void proc1(MessageEventArgs e)
{
// Process Message
}
}
class DataClient
{
public event MessageReceievedHandler MessageReceived;
}
void main()
{
DataClient dc = new DataClient();
MessageProcessor syncProcessor = new MessageProcessor(dc); // This one is high priority and needs to process all sync immediately when they arrive before any data messages
MessageProcessor dataProcessor= new MessageProcessor(dc); // This one can process the data as it has time when sync messages are not being processed.
// do other stuff
}
The reason for doing this, I have a server that is sending messages over a UDP stream. It will send sync messages before a burst of data. I realize both handlers will fire when a sync message is received, but to decrease latency I would like the syncProcessor objects events processed before the dataProcessor events. This would decrease the latency of the Sync Message being processed.
In addition, someone else on my team may want to register events to process specific messages also. They may have their own object that will register an event (May not be MessageProcessor), even still the Sync message should have as low latency as possible.
EDIT Made the objective more clear with a better example.
When you subscribe to an event multiple times, there is no possible way to be sure of the execution order of your handlers when the event is fired.
According to this answer, the order in the subscription order, but as the post author said, it's an implementation detail and you must not rely on it.
You could of course write your own "event manager" (see dirty example below) that executes your handlers in a known order, but I don't think it would be a good idea. Maybe you should re-design your event to remove your requirement.
public class MyClass
{
// Could be anything...
public delegate void MyEventHandler(object sender, EventArgs e);
public event MyEventHandler TestEvent;
public void Test()
{
if (this.TestEvent != null)
{
this.TestEvent(this, EventArgs.Empty);
}
}
}
public class EventManager
{
private List<EventHandler> Handlers = new List<EventHandler>();
public void AddHandler(EventHandler handler)
{
this.Handlers.Add(handler);
}
public void RemoveHandler(EventHandler handler)
{
this.Handlers.Remove(handler);
}
public void Handler(object sender, EventArgs e)
{
foreach (var z in this.Handlers)
{
z.Invoke(sender, e);
}
}
}
private static void Main(string[] args)
{
MyClass test = new MyClass();
EventManager eventManager = new EventManager();
// Subscribes to the event
test.TestEvent += eventManager.Handler;
// Adds two handlers in a known order
eventManager.AddHandler(Handler1);
eventManager.AddHandler(Handler2);
test.Test();
Console.ReadKey();
}
private static void Handler1(object sender, EventArgs e)
{
Console.WriteLine("1");
}
private static void Handler2(object sender, EventArgs e)
{
Console.WriteLine("2");
}
In this case, you are better off simply calling the second event at the end of the first event, etc.
If this is your own event that you defined, then your best bet might be to extend it to have a BeforeMessageReceived, MessageReceived and AfterMessageReceived events. (okay, so maybe MessageProcessed would be a better root, since you can know before a message is received).
This will give you more control over exactly where different event handlers occur.
You see the same before, event, after patten all over the place.
Im going to go out on a limb and say no. AFAIK events are dispatched ASYNCHRONOUSLY by nature. So that will be dispatched in the order they are bound. however the results may return in a different order. The only way would be to dispatch your 2nd event inside the callback for the first event. This is not language specific, just more on the architecture of events.
In your example since the calls are void y not run proc2 at the end of proc1?

Propagating a "volatile" property

I put "volatile" because it's only vaguely so.
I have a class which has a property called StopRequested. This flag can be set by other threads at any time, and needs to indicate to my code that it should stop what it's doing and exit (this is a Windows Service based process, and when Stop is called, all processing needs to clean up and stop).
I wish to create some other classes to do the actual brunt of the processing work, however these classes also have to be aware of the "stop" flag. You can't just pass the flag because it will pass a copy, and you can't pass properties as ref types.
So how do you propagate a property that might change at any time into other classes?
The only thing I can think of is to pass a reference to the parent class, but I dislike coupling the worker classes to the parent for one flag. Any suggestions would be appreciated.
EDIT:
Here's a basic example:
public class A
{
public bool StopRequested { get; set; }
private Worker = new Worker();
public void DoWork();
{
worker.DoWork();
}
}
public class Worker
{
public void DoWork()
{
while(!StopRequested)
{
....
}
}
}
You could have each of your worker classes have their own StopRequest property and then just set that whenever StopRequest is flagged.
private List<IStopable> WorkerClasses = new List< IStopable > ()
public Bool StopRequest{
get
{
return _stopRequest;
}
set
{
_stopReqest = value;
foreach (var child in WorkerClasses)
child.StopRequest = value;
}
}
Like Rubens said, use an event. What you described basically defines event to a T:
Propagate a property change to other classes.
There is actually a facility in .NET that provides this already, albeit in a generic way: INotifyPropertyChanged. This interface provides a single event, PropertyChanged, that allows a class to notify any listeners of any property change.
In your case, you could easily provide your own interface that is more specific:
interface IStopNotifier
{
event EventHandler StopRequested;
}
This interface would be implemented by your main work manager (whatever it is), and could propagate itself like so:
class WorkManager: IStopNotifier
{
public event EventHandler StopRequested;
protected void OnStopRequested()
{
if (StopRequested != null) StopRequested(this, new EventArgs());
}
public void StopAllWorkers()
{
OnStopRequested();
}
public Worker CreateWorker<T>()
where T: Worker
{
var worker = new T(this);
return worker;
}
}
class abstract Worker: IDisposable
{
public Worker(IStopNotifier stopNotifier)
{
stopNotofier.StopRequested += HandleStopRequested;
}
private IStopNotifier m_stopNotifier;
private bool m_stopRequested = false;
internal void HandleStopRequested(object sender, EventArgs e)
{
m_stopRequested = true;
}
public void Dispose()
{
m_stopNotifier.StopRequested -= HandleStopRequested;
}
}
Why don't to create an event to handle stop requests?

Categories