3

当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.

- 更新 -

两位演员如下:

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));
        }
    }
}

这是检查状态的测试:

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();
    }
}
4

1 回答 1

5

您收到一封死信通知,这意味着您尝试发送的消息无法送达。您尝试向其发送消息的参与者可能已经死亡,或者它可能从未存在过。在这种情况下,它似乎是后者。

我注意到ActorSystemProductActor的错误消息 ( catalogSystem) 与代码 ( ProductSystem) 中的名称不同。

使用 your ActorSelection,您将向错误的演员路径发送消息ActorSystem,向不存在演员的演员路径发送消息。因此,DeadLetters 注意到了。假设ProductActor创建为 中的顶级参与者catalogSystem,您尝试发送到的路径是正确的(/user/ProductActor/validator),但参与者系统名称不是(应该是catalogSystem但这里是ProductSystem)。

如何修复它

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

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

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

可以从中吸取两个教训。

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

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

有了ActorSelection,你就没有这样的保证了。它有点像UDP——你只是在一个地址发送消息,不知道是否有人在监听。

这就提出了“那么我应该什么时候使用ActorSelection?”的问题。我遵循的准则是使用ActorSelectionwhen:

  1. 出于某种原因,我需要利用演员路径中的通配符选择。
  2. 我需要向远程演员系统上的演员发送初始消息,所以我实际上还没有处理它(并且不能保证它曾经存在过

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

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

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; }
    }
}

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

Context.ActorSelection(ActorPaths.ProductValidatorActor.Path).Tell(message);
于 2015-05-18T17:29:22.750 回答