AKKA.NET 和 DeathWatchNotification

标签 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.

--更新--

两个 Actor 如下:

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

最佳答案

您收到死信通知,这意味着您尝试发送的消息无法送达。您要向其发送消息的 Actor 可能已经死了,也可能根本不存在。在这种情况下,它似乎是后者。

我注意到您的 ProductActor 所在的 ActorSystem 的名称在您的错误消息 (catalogSystem) 与您的代码 ( ProductSystem).

使用 ActorSelection,您将消息发送到错误的 ActorSystem 中的角色路径,发送到不存在角色的角色路径。因此,死信通知。假设 ProductActor 被创建为 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发送到IActorRef,而不是ActorSelection。通过 IActorRef,您可以知道 Actor 在过去的某个时间点已经存在。这是 Akka 框架的保证,所有 IActorRef 都在某个时刻存在,即使 actor 现在已经死了。

对于 ActorSelection,您没有这样的保证。有点像UDP ——你只是在不知道是否有人在听的情况下向一个地址发送消息。

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

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

第 2 课:不要在您的 actor 代码中增加手指 actor 路径

如果您需要使用 ActorSelection,请将路径放在共享类中,然后让所有其他 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; }
    }
}

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

Context.ActorSelection(ActorPaths.ProductValidatorActor.Path).Tell(message);

关于AKKA.NET 和 DeathWatchNotification,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30287258/

相关文章:

c# - 有没有办法等待 Actor 完全停止?

persistence - 启动时如何从数据库中预热 Actor 的状态?

f# - 如何在 F# 中使用 Akka.Streams.*.ConcatMany?

c# - 参与者内部的异步 API 调用和异常

akka - 如何对 Actor 集合进行查询

asp.net - ASP.NET 中的 Akka.NET Actor 系统

c# - 使用 C# 库中的 Akka.Net actor 调用 F# 库导致 TypeInitializationException

c# - 如何在 Akka.Net Receive Actor 中接收任何类型的消息

ssl - Akka.NET TLS 实现

c# - Akka.NET 参与者和包装器(可能与 Rx 一起使用)