2017-04-12 85 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一起去吧,節省您的頭痛......