当 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
)。
如何修复
那么如何解决呢?两种选择:
- 在您的
ActorSelection
中使用正确的路径,如下所示:Context.ActorSelection("akka://catalogSystem/user/ProductActor/validator").Tell(message);
。虽然这可行,但这是错误的答案。 - 由于您将
ProductValidatorActor
创建为ProductActor
的子级,只需将子级的IActorRef
存储在父级中,然后发送消息直接给它。这是我推荐的方法。在这种特殊情况下,您根本不需要ActorSelection
。
它现在可以工作了,但是我们可以在这里学到什么?
从中可以吸取两个教训。
第 1 课:不要在不需要时使用 ActorSelection
通常,您应该将消息Tell
发送到IActorRef
,而不是ActorSelection
。通过 IActorRef
,您可以知道 Actor 在过去的某个时间点已经存在。这是 Akka 框架的保证,所有 IActorRef
都在某个时刻存在,即使 actor 现在已经死了。
对于 ActorSelection
,您没有这样的保证。有点像UDP ——你只是在不知道是否有人在听的情况下向一个地址发送消息。
这就提出了“那么我什么时候应该使用 ActorSelection
?”的问题。我遵循的准则是在以下情况下使用 ActorSelection
:
- 出于某种原因,我需要在 actor 路径中利用通配符选择。
- 我需要向远程 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/