AKKA.NET and DeathWatchNotification
I get the following message when ProductActor tries to tell ValidatorActor to validate this message. Although I see this message, I am getting the expected result.
I have not tried to send a message from ProductActor to myself. Why else am I getting the following message?
[INFO][5/17/2015 8:06:03 AM][Thread 0012][akka://catalogSystem/user/productActor] Message DeathWatchNotification from akka://catalogSystem/user/productActor to akka://catalogSystem/user/productActor was not delivered. 1 dead letters encountered.
- UPDATE -
Below are two participants:
public class ProductActor : UntypedActor
{
protected override void OnReceive(object message)
{
if (message is ReportableStatusChanged)
{
_reportableState = ((ReportableStatusChanged) message).ReportableState;
}
else
{
if (message is RetrieveProductState)
{
var state = new ProductState()
{
ReportableState = _reportableState
};
Sender.Tell(state);
}
else
{
Context.ActorSelection("akka://ProductSystem/user/ProductActor/validator").Tell(message);
}
}
}
protected override void PreStart()
{
Context.ActorOf(Props.Create(() => new ProductValidatorActor()), "validator");
base.PreStart();
}
private IReportableState _reportableState;
}
public class ProductValidatorActor : UntypedActor
{
protected override void OnReceive(object message)
{
if (message is ChangeReportableStatus)
{
Sender.Tell(new ReportableStatusChanged(ReportableStates.ReportableState));
}
}
}
This is a test to check the status:
class ChangeReportableStatusTest
{
public void Do()
{
var system = ActorSystem.Create("catalogSystem");
var ProductActor = system.ActorOf(Props.Create<ProductActor>(), "productActor");
ProductActor.Tell(new ChangeReportableStatus(true));
Thread.Sleep(50);
var state = ProductActor.Ask<ProductState>(new RetrieveProductState());
Console.WriteLine("Reportable State: " + (state.Result.ReportableState == ReportableStates.ReportableState ? "TRUE" : "FALSE"));
system.Shutdown();
system.AwaitTermination();
Console.WriteLine("Please press any key to terminate.");
Console.ReadKey();
}
}
source to share
You receive a dead letter notification, which means that the message you are trying to send could not be delivered. The actor you are trying to send the message to may be dead or may have never existed. In this case, it appears to be the latter.
I noticed that the name ActorSystem
yours lives in is ProductActor
different from your error message ( catalogSystem
) and your code ( ProductSystem
).
By using, ActorSelection
you send a message to the actor's path in the wrong ActorSystem
way to the actor's path, where there is no character. Hence, DeadLetters get noticed. Assuming it ProductActor
is instantiated as a top-level actor in catalogSystem
, the path you are trying to post is correct ( /user/ProductActor/validator
), but the system name of the actor is not (it should be catalogSystem
, but here it is ProductSystem
).
How to fix it
So how do you fix this? Two options:
- Use the correct path in
ActorSelection
the following manner:Context.ActorSelection("akka://catalogSystem/user/ProductActor/validator").Tell(message);
. While this works, it is not the correct answer. - Since you are creating
ProductValidatorActor
as a childProductActor
, just store theIActorRef
child in the parent and send messages to it directly. This is the approach I recommend. In this particular case, you don't need it at allActorSelection
.
Now it works, but what can we find out here?
There are two lessons to be learned from this.
Lesson 1: Don't Use ActorSelection
When You Don't Need It
Generally, you should be s Tell
messages IActorRef
, not ActorSelection
s. With IActorRef
you know that the actor existed at some point in time in the past. This is the Akka framework's guarantee that everyone has IActorRef
existed at some point, even if the actor is now dead.
Since ActorSelection
you have no such guarantee. It's kind of like UDP - you just run messages at the address, unaware that someone is listening.
The question is, "so when should I use ActorSelection
?" I use the following guide ActorSelection
when:
- For some reason I need to use wildcard selection in the actor tracks.
- I need to send an original message to an actor on a remote actor system, so I don't have a descriptor yet (and I don't have a guarantee that it was ever ex
Lesson 2: Don't Move the Accompaniment Tracks of Your Actor Code
If you need to use ActorSelection
s, put the paths in a generic class, and then everyone else will refer to that class. Something like that:
using Akka.Actor;
namespace ProductActors
{
/// <summary>
/// Static helper class used to define paths to fixed-name actors
/// (helps eliminate errors when using <see cref="ActorSelection"/>)
/// </summary>
public static class ActorPaths
{
public static readonly ActorMetaData ProductValidatorActor = new ActorMetaData("validator", "akka://ProductActors/user/validator");
public static readonly ActorMetaData ProductCoordinatorActor = new ActorMetaData("coordinator", "akka://ProductActors/user/commander/coordinator");
}
/// <summary>
/// Meta-data class
/// </summary>
public class ActorMetaData
{
public ActorMetaData(string name, string path)
{
Name = name;
Path = path;
}
public string Name { get; private set; }
public string Path { get; private set; }
}
}
... which can be referenced like this:
Context.ActorSelection(ActorPaths.ProductValidatorActor.Path).Tell(message);
source to share