2017-04-12 48 views
0

假设我有一个演员谁是负责将消息路由到儿童演员的集合,基于一些关键的,所以它的内部状态是这样的:管理阿卡儿童演员地图的正确方法是什么?

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

希望上面的代码足以得到我想要做的一般想法。请注意,我正在使用地图键作为子actor的名称。问题是,上面的图案不处理添加的情况下,删除和添加临门消息相同的密钥 - 它往往不能在第二添加有:

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

显然,在停止童星删除消息是异步的,这就是为什么它不起作用,我正在努力查看解决方案。我已经注意到从Akka docs以下点,这正好说明我的问题:

虽然可以在以后的时间来创建一个演员用相同的路径[...]这是不好的做法[。 ..]。

在特定情况下做这件事可能是正确的,但确保将处理这件事仅仅局限于演员的主管,因为那是唯一可以可靠地检测到名称的正确注销的演员,在此之前新孩子的创造将失败。

那么,重新使用演员的路径(使用地图键作为演员的名字)在这里做正确的事情?如果是这样,我该如何“可靠地检测到正确注销名称”?如果没有,我是否应该为每个演员的名字分配一个UUID?如果孩子是持久性行动者,这会导致问题吗?(因为可以在前一个孩子被正确终止之前创建具有相同持久性ID的新孩子)?

回答

1

您可以watchActorRef的状态在Actor已终止时获取通知。如果已终止派发但您的主管尚未收到确认,则ActorRef将被视为“陈旧”。

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

这递归消息意味着,你的上司会不断地尝试直到终止完成。

会有一个问题,如果一个RouteToChild到达而一个ActorRef是陈旧的,但解决这种情况是开放式,并在问题没有得到指定...

千万别做

说了这么多,我同意在问题中的引用:“这不是好习惯”。

与UUIDs一起去吧,节省您的头痛......