6

我正在使用 Akka.NET 实现一个演员系统,其中一些演员是按需创建的,并在可配置的空闲期后被删除(为此我使用 Akka 的“ReceiveTimeout”机制)。这些参与者中的每一个都由一个密钥标识,并且不应存在两个具有相同密钥的参与者。

这些参与者当前由一个共同的主管创建和删除。如果具有此键的参与者尚不存在,则可以要求主管返回对匹配给定键的参与者的引用,方法是返回现有的或创建新的。当演员收到“ReceiveTimeout”消息时,它会通知主管,主管反过来用“PoisonPill”杀死它。

在删除其中一个演员后立即向其中一个演员发送消息时,我遇到了问题。我注意到向死去的演员发送消息不会产生异常。更糟糕的是,当发送“询问”消息时,发送者仍然被阻止,无限期地等待(或直到超时)等待他永远不会收到的响应。

我首先想到了 Akka 的“Deatchwatch”机制来监控演员的生命周期。但是,如果我没记错的话,监视actor发送的“终止”消息将像任何其他消息一样被监控actor异步接收,因此问题可能仍然发生在目标actor死亡和接收它之间“终止”消息。

为了解决这个问题,我这样做是为了让任何要求主管参考这样一个演员的人都必须向主管发送一个“关闭会话”消息,以便在他不再需要它时释放演​​员(这是透明地完成的由一次性“ActorSession”对象)。只要演员有任何打开的会话,主管就不会删除它。

我想这种情况很常见,因此我想知道是否没有更简单的模式可以解决这类问题。任何建议将不胜感激。

4

2 回答 2

3

在删除其中一个演员后立即向其中一个演员发送消息时,我遇到了问题。我注意到向死去的演员发送消息不会产生异常。

这是设计使然。在尝试发送消息时,您永远不会收到异常 - 它只会被路由Deadletters并记录。有很多原因我不会在这里讨论,但最重要的是这是预期的行为。

DeathWatch是这项工作的正确工具,但正如您所指出的 -Terminated在您已经向该演员发送消息后,您可能会收到一条消息。

比跟踪打开/关闭会话更简单的模式是简单地使用来自收件人的确认/回复消息,使用Ask+ 等待 + 硬超时。当然,不利的一面是,如果您的收件人演员有很多长时间运行的操作,那么您可能会在发件人内部长时间阻塞。

您可以使用的另一个选项是重新设计您的接收参与者以充当状态机,并具有软终止终止状态,用于耗尽与潜在发件人的连接/引用。这样,原始参与者仍然可以回复和接受消息,但让调用者知道它不再可以工作。

于 2014-12-23T08:13:41.997 回答
0

我通过 Akka 的集群分片机制创建的实体 actor 解决了这个问题:

如果实体的状态是持久的,您可以停止不用于减少内存消耗的实体。这是通过实体参与者的应用程序特定实现来完成的,例如通过定义接收超时 (context.setReceiveTimeout)。如果消息在实体停止时已经入队,则邮箱中的入队消息将被丢弃。为了在不丢失此类消息的情况下支持优雅钝化,实体 Actor 可以将 ShardRegion.Passivate 发送到其父 Shard。Passivate 中指定的包装消息将被发送回实体,然后该实体应该自行停止。在接收到 Passivate 和终止实体之间,传入的消息将由 Shard 缓冲。此后,此类缓冲消息被传递到实体的新化身。

于 2017-11-14T09:26:49.893 回答