AKKA.NET和DeathWatchNotification

won*_*rld 3 akka.net

ProductActor尝试告诉ValidatorActor验证消息时,我收到以下消息.虽然我看到了这条消息,但我得到了预期的结果.

我没有尝试从ProductActor向自己发送消息.为什么我仍然收到以下消息?

[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.
Run Code Online (Sandbox Code Playgroud)

--UPDATE--

下面给出了两位演员:

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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是检查状态的测试:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*ewS 5

您收到了死信通知,这意味着您尝试发送的邮件无法送达.你试图发送消息的演员可能已经死了,或者它可能从未存在过.在这种情况下,它似乎是后者.

我注意到的名字ActorSystem,你的ProductActor生活中是在错误消息中不同的(catalogSystem)对你的代码(ProductSystem).

有了你ActorSelection,你就会向一个错误的演员路径发送一条消息到一个ActorSystem没有演员存在的演员路径.因此DeadLetters通知.假设ProductActor创建为顶级actor,catalogSystem您尝试发送的路径是正确的(/user/ProductActor/validator),但是actor系统名称不是(应该在catalogSystem这里ProductSystem).

如何解决它

那么你如何解决它?两种选择:

  1. 在你的ActorSelection喜欢中使用正确的路径:Context.ActorSelection("akka://catalogSystem/user/ProductActor/validator").Tell(message);.虽然这有效,但这是错误的答案.
  2. 由于您创建ProductValidatorActor了子项ProductActor,只需将IActorRef子项存储在父项中,并直接向其发送消息.这是我推荐的方法.在这种特殊情况下,您根本不需要ActorSelection.

它现在有效,但我们可以在这里学到什么?

这有两个教训.

第1课:不使用ActorSelection时不需要它

通常,您应该将Tell消息发送到IActorRefs而不是ActorSelections.有了IActorRef,你知道演员在过去的某个时间点存在过.这是Akka框架的保证IActorRef,即使演员现在已经死了,所有这些都存在于某个时刻.

有了ActorSelection,你没有这样的保证.它有点像UDP - 你只是在地址上发送消息而不知道是否有人在听.

这提出了"我ActorSelection什么时候应该使用?"的问题.我遵循的准则是使用ActorSelection时间:

  1. 出于某种原因,我需要利用actor路径中的通配符选择.
  2. 我需要向一个远程actor系统上的actor发送一条初始消息,所以我实际上还没有它的句柄(并且不保证它是ex

第2课:不要在你的演员代码中胖手指演员路径

如果需要使用ActorSelections,请将路径放在共享类中,然后让所有其他actor引用该类.像这样的东西:

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

...然后可以这样引用:

Context.ActorSelection(ActorPaths.ProductValidatorActor.Path).Tell(message);
Run Code Online (Sandbox Code Playgroud)

  • 是的,但是在你的`ProductActor`中,你仍然将你的消息发送到`ProductSystem`:`Context.ActorSelection("akka:// ProductSystem/user/ProductActor/validator").Tell(message);` (2认同)