Stopping a repeating scheduled message - akka.net

We want an actor to stop itself after a period of some inactivity (i.e. after it hasnt received a certain kind of message for x minutes). I don't see any built-in support for this, so I've opted to use the scheduler.
The actor itself sets a scheduled message from itself to itself, as follows:
Context
.System
.Scheduler
.ScheduleTellRepeatedly(_expiryInterval, _expiryInterval, Self, new ExpiryCheckMessage(), Self);
On receiving this message:
Receive<ExpiryCheckMessage>(x => {
if(IsExpired())
{
Context.Stop(Self);
}
});
But after expiring and stopping the actor the scheduled messages keep sending resulting in deadletters.
What is the best way to stop a scheduled message in this case?

NB: I'm familiar with Akka on the JVM, not on .Net.
From the Akka docs for ScheduleTellRepeatedly it appears that there's an optional cancelable parameter of type ICancelable. So I would imagine that something like (this is literally the first C# I've ever attempted to write, so apologies in advance):
// Somewhere in the actor's scope
var cancellationKey = new Cancelable(Context.System.Scheduler);
Context
.System
.Scheduler
.ScheduleTellRepeatedly(
_expiryInterval,
_expiryInterval,
Self,
new ExpiryCheckMessage(),
Self,
cancellationKey
);
Receive<ExpiryCheckMessage>(x =>
if (IsExpired()) {
cancellationKey.Cancel();
Context.Stop(Self);
}
}

Related

How can I get a non-blocking infinite loop in a Kotlin Actor?

I would like to consume some stream-data using Kotlin actors
I was thinking to put my consumer inside an actor, while it polls in an infinite loop while(true). Then, when I decide, I send a message to stop the consumer.
Currently I have this:
while(true) {
for (message in channel){ <--- blocked in here, waiting
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
The problem
The problem with this is that it only runs when I send a message to the actor, so my consumer is not polling the rest of the time because channel is blocking waiting to receive the next message
Is there any alternative?, someone with the same issue?, or something similar to actors but not blocked by channel in Kotlin?
Since the channel is just a Channel (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html) you can first check if the channel is empty and if so start your polling. Otherwise handle the messages.
E.g.
while(true) {
while (channel.isNotEmpty()) {
val message = channel.receive()
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
In the end I used AKKA with Kotlin, I'm finding much easier this way
You should use postDelayed(), for example:
final Runnable r = new Runnable() {
public void run() {
// your code here
handler.postDelayed(this, 1000)
}
}
You can change 1000 with the the millisecond delay you want. Also I highly recommend to put your code inside a thread (if you are not already have) to prevent ANR (App Not Responding)

ServiceStack RedisMqServer: No way to add or remove channels in runtime?

My, already "legacy" by now, implementation of a pub/sub solution using ServiceStack quickly ran out of clients, when it reached the 20 client limit.
We do something like:
_redisConsumer = MqClientFactory.Instance.GetRedisClient(); // Returns a IRedisClient
_subscription = _redisConsumer.CreateSubscription();
_subscription.OnSubscribe = channel => CoreLog.Instance.Info($"Subscription started on {eventChannelName}");
_subscription.OnUnSubscribe = channel => CoreLog.Instance.Warning($"Unsubscribed from {eventChannelName}");
_subscription.OnMessage = (channel, msg) =>
{
try
{
onMessageReceived(CoreRequestJsonEnvelope.CreateCoreRequestFromJson(msg));
}
catch (Exception ex)
{
CoreLog.Instance.Exception(ex);
}
};
// Since it blocks execution, we put this in a Task:
Task.Run(() =>
{
try
{
_subscription.SubscribeToChannels(eventChannelName); // blocking
}
catch(Exception e)
{
}
});
and when we have enough different channels to listen too, it runs out.
I then thought, that maybe instead of taking a new IRedisClient for each subscription, I could use the same IRedisClient for all of them, so:
_redisConsumer = mySavedRedisClient;
...
but that returns Unknown reply on multi-request after a few seconds/executions.
Lastly, I looked at the RedisPubSubServer, but it seems that I need to specify the channels in the constructor, and I cannot change after that. I do need to add and remove channels in runtime, and channels are not known from start.
What is the recommended approach?
Is it to increaase the Max-limit and continue as before?
Is it to use RedisPubSub, but how to handle dynamic channels?
What does "unknown reply on multi-request" actually mean?
Thanks!
It's not clear what 20 client limit you're referring to & how the client limit is dependent on channels or subscribers, but if this is your App own limit than sounds like increasing it would be the easiest solution.
ServiceStack.Redis doesn't support changing the subscribed channels after a subscription has started. Instead of managing the IRedisSubscription yourself you may want to consider ServiceStack.Redis Managed Pub/Sub Server which manages the background subscription thread with added resiliency and support for auto retries.
Whilst you can't change the subscribed channels at runtime, you can modify the modify the Channels collection and restart the subscription to create a new subscription to the updated channels list, e.g:
var pubSub = new RedisPubSubServer(clientsManager, chan1);
pubSub.Start();
//...
pubSub.Channels = new[] { chan1, chan2 };
pubSub.Restart();
Otherwise depending on your use-case you may be able to subscribe to a channel pattern which allows you to subscribe to a multiple dynamic channels matching wildcard channel pattern:
var pubSub = new RedisPubSubServer(clientsManager) {
ChannelsMatching = new[] { "chan:*" }
}
.Start();
Where it will handle any messages clients send that matches the channel pattern.

How to expect some messages and ignore others with akka.net testkit?

I have a test for an actor that might respond with some unexpected messages but eventually it must respond with a particular known message.
So in essence I want an assertion that will within in some timespan ignore other messages but expect a known message, like so:
[TestMethod]
[TestCategory("Integration")]
public async Task Should_fetch_fund_shareclass_and_details_from_test_service()
{
var testIsins = new HashSet<string> {"isin1", "isin2", "isin3"};
var props = Props.Create(() => new DataFetchSupervisor());
var actor = Sys.ActorOf(props, "fetchSupervisor");
Within(TimeSpan.FromSeconds(30), () =>
{
actor.Tell(new StartDataFetch(testIsins));
//ignore unexpected messages here
var fetchComplteMsg = ExpectMsg<DataFetchComplete>();
});
}
So now this will fail because I get some other messages before DataFetchComplete message.
As always, thanks in advance for any help.
Akka.TestKit class has a number of different versions of ExcpectMsg or equivalent checkers. The one you're looking for is probably a FishForMessage. It takes a predicate and will ignore all incoming messages as long as they will fail to pass predicate's condition. Once a passing message is found this check will complete and your code may be continued.
You can also use the TestKit.IgnoreMessages method, which will accept a delegate function specifying which types of messages you wish to ignore while waiting for your target message.

Is there an easy way to subscribe to the default error queue in EasyNetQ?

In my test application I can see messages that were processed with an exception being automatically inserted into the default EasyNetQ_Default_Error_Queue, which is great. I can then successfully dump or requeue these messages using the Hosepipe, which also works fine, but requires dropping down to the command line and calling against both Hosepipe and the RabbitMQ API to purge the queue of retried messages.
So I'm thinking the easiest approach for my application is to simply subscribe to the error queue, so I can re-process them using the same infrastructure. But in EastNetQ, the error queue seems to be special. We need to subscribe using a proper type and routing ID, so I'm not sure what these values should be for the error queue:
bus.Subscribe<WhatShouldThisBe>("and-this", ReprocessErrorMessage);
Can I use the simple API to subscribe to the error queue, or do I need to dig into the advanced API?
If the type of my original message was TestMessage, then I'd like to be able to do something like this:
bus.Subscribe<ErrorMessage<TestMessage>>("???", ReprocessErrorMessage);
where ErrorMessage is a class provided by EasyNetQ to wrap all errors. Is this possible?
You can't use the simple API to subscribe to the error queue because it doesn't follow EasyNetQ queue type naming conventions - maybe that's something that should be fixed ;)
But the Advanced API works fine. You won't get the original message back, but it's easy to get the JSON representation which you could de-serialize yourself quite easily (using Newtonsoft.JSON). Here's an example of what your subscription code should look like:
[Test]
[Explicit("Requires a RabbitMQ server on localhost")]
public void Should_be_able_to_subscribe_to_error_messages()
{
var errorQueueName = new Conventions().ErrorQueueNamingConvention();
var queue = Queue.DeclareDurable(errorQueueName);
var autoResetEvent = new AutoResetEvent(false);
bus.Advanced.Subscribe<SystemMessages.Error>(queue, (message, info) =>
{
var error = message.Body;
Console.Out.WriteLine("error.DateTime = {0}", error.DateTime);
Console.Out.WriteLine("error.Exception = {0}", error.Exception);
Console.Out.WriteLine("error.Message = {0}", error.Message);
Console.Out.WriteLine("error.RoutingKey = {0}", error.RoutingKey);
autoResetEvent.Set();
return Task.Factory.StartNew(() => { });
});
autoResetEvent.WaitOne(1000);
}
I had to fix a small bug in the error message writing code in EasyNetQ before this worked, so please get a version >= 0.9.2.73 before trying it out. You can see the code example here
Code that works:
(I took a guess)
The screwyness with the 'foo' is because if I just pass that function HandleErrorMessage2 into the Consume call, it can't figure out that it returns a void and not a Task, so can't figure out which overload to use. (VS 2012)
Assigning to a var makes it happy.
You will want to catch the return value of the call to be able to unsubscribe by disposing the object.
Also note that Someone used a System Object name (Queue) instead of making it a EasyNetQueue or something, so you have to add the using clarification for the compiler, or fully specify it.
using Queue = EasyNetQ.Topology.Queue;
private const string QueueName = "EasyNetQ_Default_Error_Queue";
public static void Should_be_able_to_subscribe_to_error_messages(IBus bus)
{
Action <IMessage<Error>, MessageReceivedInfo> foo = HandleErrorMessage2;
IQueue queue = new Queue(QueueName,false);
bus.Advanced.Consume<Error>(queue, foo);
}
private static void HandleErrorMessage2(IMessage<Error> msg, MessageReceivedInfo info)
{
}

notify listener inside or outside inner synchronization

I am struggling with a decision. I am writing a thread-safe library/API. Listeners can be registered, so the client is notified when something interesting happens. Which of the two implementations is most common?
class MyModule {
protected Listener listener;
protected void somethingHappens() {
synchronized(this) {
... do useful stuff ...
listener.notify();
}
}
}
or
class MyModule {
protected Listener listener;
protected void somethingHappens() {
Listener l = null;
synchronized(this) {
... do useful stuff ...
l = listener;
}
l.notify();
}
}
In the first implementation, the listener is notified inside the synchronization. In the second implementation, this is done outside the synchronization.
I feel that the second one is advised, as it makes less room for potential deadlocks. But I am having trouble to convince myself.
A downside of the second imlementation is that the client might receive 'incorrect' notifications, which happens if it accessed and changed the module prior to the l.notify() statement. For example, if it asked the module to stop sending notifications, this notificaiton is sent anyway. This is not the case in the first implementation.
thanks a lot
It depends on where you are getting listener in your method, how many listeners you have, how the listener subscribes/unsubscribes
Assuming from your example, you have only one listener then you might be better to use critical sections (or monitors) for different parts of the class rather than locking the entire object.
You could have one lock for performing tasks within the method that are specific to the object/task at hand, and one for the listener subscribe/unsubscribe/notify (that is to ensure that the listener is not changed during a notification).
I would also use a ReadWriteLock protecting you listener references (either single or list of listeners)
Answering you comment:
I think that you should notify the listener after you have unlocked the class. This is because, the result of that notification could result in a different thread trying to gain access to the class, which it may not be able to do, under certain circumstances, leading to deadlock.
Notifying a listener (if protected like I have described) should not hold up any other thread that requires the facilities of the class. The best strategy is to create locks that are specific to the state of the class and locks that are specific to safe notification.
If you take your example of suspending notifications, this could be covered by the lock that governs notifications, so if a different thread 'suspends' notifications, either the suspend will be processed or the current notification complete, if the other thread suspends notification between the task being processed and the notification happening, the l.notify() will not happen.
Listener l = null;
synchronised(processLock_) {
... do stuff....
synchronised(notifyLock_) {
l = listener;
}
}
//
// current thread preempted by other thread that suspends notification here.
//
synchronised(notifyLock_) { // ideally use a readwritelock here...
l = allowNotify_ ? l: null;
}
if(l)
l.notify();