当前位置: 首页 > 知识库问答 >
问题:

管理Akka儿童演员地图的正确方法是什么?

钱跃
2023-03-14

假设我有一个参与者,负责根据某个键将消息路由到子参与者集合,因此其内部状态如下所示:

Map<String, ActorRef> children;

除了路由消息外,父参与者还必须支持添加和删除操作:

if(message instanceOf Add) {
    children.put(message.getKey(), getContext().actorOf(childProps, message.getKey()));
} else if (message instanceOf Remove) {
    getContext().stop(children.get(message.getKey());
    children.remove(message.getKey());
} else if (message instanceOf RouteToChild) {
    children.get(message.getKey()).forward(message, getContext());
}

希望上面的代码足以让我大致了解我要做的事情。请注意,我使用map键作为子参与者的名称。问题在于,上述模式无法处理同一个键的添加、删除和添加消息的快速连续情况-它通常在第二次添加时失败,原因是:

akka.actor.InvalidActorNameException: actor name [...] is not unique!

显然,在Remove messages上停止子参与者是异步的,这就是为什么它不起作用的原因,我正在努力寻找解决方案。我从Akka文档中注意到以下几点,它准确地描述了我的问题:

虽然可以在以后创建具有相同路径的参与者[…]这不是好的做法[……]。

在非常具体的情况下,这可能是正确的做法,但请确保将处理仅限于行为者的主管,因为这是唯一能够可靠地检测名称的适当注销的行为者,在此之前,新子级的创建将失败。

那么,在这里重用演员路径(使用map键作为演员名称)是正确的吗?如果是,我如何“可靠地检测名称的适当注销”?如果没有,我应该给每个演员的名字分配一个UUID吗?如果这些子级是持久性参与者,这会导致问题吗(因为具有相同持久性标识的新子级可以在前一个子级被正确终止之前创建)?

共有1个答案

葛飞扬
2023-03-14

您可以查看ActorRef的状态,以在参与者终止时获得通知。如果终止已发出,但您的主管尚未收到确认,则ActorRef被视为“过时”。

如果一个Add出现在一个过时的参与者身上,那么您只需再次将Add发送给自己,希望最终终止:

HashSet<String> staleActorRefs = new HashSet<String>();

if(message instanceOf Add) {
    if(staleActorRefs.contains(message.getKey())) {
      getSelf().forward(message, getContext()); 
    } else {
      children.put(message.getKey(), getContext().watch(getContext().actorOf(childProps, message.getKey())));
    }
} else if (message instanceOf Remove) {
    getContext().stop(children.get(message.getKey());
    staleActorRefs.add(message.getKey());
    children.remove(message.getKey());
} else if (message instanceOf RouteToChild) {
    children.get(message.getKey()).forward(message, getContext());
} else if (message instanceOf Terminated) {
    staleActorRefs.remove(message.actor().path().name());
}

这种递归消息意味着您的主管将不断尝试添加,直到终止完成。

如果当ActorRef过时时,RouteToChild到达,则会出现问题,但该情况的解决方案是开放式的,并且未在问题中指定。。。

不要这样做

话虽如此,我同意问题中的引述:“这不是好做法”。

使用UUID,省去你的头痛。。。

 类似资料:
  • 我对阿克卡很陌生,我有一个(希望)简单的问题。我有一个参与者需要重复执行某个小的子任务——也就是说,每次这个参与者收到消息时,它都必须执行N个子任务。这个子任务是我指定给儿童演员的。我的问题是,我是否应该为每个子任务创建一个新的子角色实例?或者我应该简单地产生一个孩子演员,并发送N条消息?在这种情况下,最好的做法是什么? 为了更好地说明我的问题,这里有两个简化的示例(在Java中-但希望对Scal

  • 我经常发现自己使用一个“主”角色,为子任务创建许多子角色。当子任务完成时,主角也应该停止自己。所以当时,我观察子角色并停止主角色context.children.is。 我经常使用这种模式,但因为我从未读过这方面的文章。我不确定,这是一个好主意还是失败的演员有问题。。。? 我已经读过Akka 2中的关机模式,但是这种方法在Java中似乎比我的解决方案更复杂? 以下是我针对具有两个子任务的主要参与者

  • 让我们假设一个使用Akka Typed实现的应用程序有一个持久执行元。这个持久执行元作为其操作的一部分创建了瞬态(或非持久)子执行元,每个子执行元都有一个唯一的ID,这些ID是持久状态的一部分。持久执行元还需要一些与其子级通信的方式,但我们不希望持久化子级的,因为它们实际上不是状态的一部分。在恢复时,持久参与者应该基于恢复的状态重新创建它的子级。这听起来并不像是一个很不寻常的用例,我正在试图弄清楚

  • 然后,Actor A将json解析为对象序列,然后通过ask将它们发送给Actor B。Actor B应该最终通过将它们发送给其他Actor来处理这些对象,但目前只是返回一般的响应。 ActorA将来会接收到一般的响应,然后解析到JSON,然后通过OK响应返回给控制器。或者至少这是应该发生的。 发生了什么:控制器发送到ActorA,ActorA发送到Actorb。ActorB向Actora发送一般

  • 我是Akka的新手,我想知道我应该如何处理将工作委托给其他(儿童)演员的演员,但在哪里: 其中一些儿童演员必须按特定顺序参与;和 其中一些子参与者可以以任何顺序参与,并且可以真正地与主/父参与者所做的事情异步执行 假设我有以下儿童演员(不管他们做什么): 假设我有以下调用它们的父参与者: 如你所见: 必须首先“参与”(由家长调用),我们必须等待家长的响应,然后才能继续参与/调用、或 换句话说,当消

  • 我所做的: null 更新:我发现了问题;它是由于通过池消耗Redis连接而导致的,并且从未释放它们。但我还有第二个问题,我在这里做的事情明智吗?