AKKA.NET和DeathWatchNotification

时间:2015-05-17 13:17:40

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

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

这是检查状态的测试:

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

1 个答案:

答案 0 :(得分:5)

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

我注意到您的ActorSystem所在的ProductActor的名称在您的错误消息(catalogSystem)与您的代码(ProductSystem)中有所不同。

使用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存储在父项中,然后直接向其发送消息。这是我推荐的方法。在这种特殊情况下,您根本不需要ActorSelection
  3. 现在有效,但我们可以在这里学到什么?

    可以从中吸取两个教训。

    第1课:在不需要的情况下不使用ActorSelection

    通常,您应TellIActorRef发送消息,而不是ActorSelection。使用IActorRef,您知道该角色过去曾在某个时间点存在过。这是Akka框架的保证,所有IActorRef都存在于某个时刻,即使演员已经死了。

    使用ActorSelection,您没有这样的保证。它有点像UDP - 你只是在一个地址发消息而不知道是否有人在听。

    这提出了&#34;我什么时候应该使用ActorSelection?&#34;我遵循的准则是在{:1>}时使用ActorSelection

    1. 出于某种原因,我需要利用actor路径中的通配符选择。
    2. 我需要向远程演员系统上的演员发送一条初始消息,所以我实际上还没有处理它(并且不能保证它不会出现
    3. 第2课:你的演员代码中没有胖手指演员路径

      如果您需要使用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);