2014-10-20 67 views
7

Akka Cluster-Sharding看起來很像用例,我必須在Akka節點上創建狀態持久actor的單個實例。Akka cluster-sharding:Can Entry actor have dynamic props

我不清楚是否有可能有一個Entry actor類型需要參數來構造它。或者,也許我需要重新考慮入門演員如何獲取這些信息。

Object Account { 
    def apply(region: String, accountId: String): Props = Props(new Account(region, accountId)) 
} 

class Account(val region: String, val accountId: String) extends Actor with PersistentActor { ... } 

ClusterSharding.start接受一個單一的Props實例來創建所有的Entry actor。

akka cluster-sharding

val counterRegion: ActorRef = ClusterSharding(system).start(
    typeName = "Counter", 
    entryProps = Some(Props[Counter]), 
    idExtractor = idExtractor, 
    shardResolver = shardResolver) 

然後它解決了基於你如何定義idExtractor接收消息的輸入演員。從碎片可以看出它的源代碼使用id作爲名稱對於給定的輸入主角實例:

def getEntry(id: EntryId): ActorRef = { 
val name = URLEncoder.encode(id, "utf-8") 
context.child(name).getOrElse { 
    log.debug("Starting entry [{}] in shard [{}]", id, shardId) 

    val a = context.watch(context.actorOf(entryProps, name)) 
    idByRef = idByRef.updated(a, id) 
    refById = refById.updated(id, a) 
    state = state.copy(state.entries + id) 
    a 
} 

}

看來我應該不是有我的入學演員弄不清它的區域和accountId按它的名字給出,儘管這會讓我感覺有點不好意思,因爲現在我會從字符串中解析出來,而不是直接獲取值。這是我最好的選擇嗎?

回答

10

我和你的情況非常相似。我沒有一個確切的答案,但我可以與你和讀者分享我所做的/嘗試/想到的。

選項1)正如你所提到的,你可以從你如何命名你的東西和解析路徑中提取id,shard和region信息。好處是 a)這很容易做到。 缺點是 a)Akka將actor路徑編碼爲UTF-8,所以如果你使用任何東西作爲不是標準url字符的分隔符(比如||或w/e),你需要先解碼它來自utf8。請注意,Akka utf8內部是以編碼方式硬編碼的,因此無法像在函數中一樣提取編碼格式,因此如果明天阿卡變化了,您也必須修改代碼。 b)你的系統不再保持同態(你的意思是「它感覺有點不好」)。這意味着您將增加風險,即您的數據有一天可能會將您的信息分隔符字符串包含爲有意義的數據,並且您的系統可能會陷入困境。

選項2)如果分支不存在,分片將產生你的演員。所以你可以強制你的代碼總是發送一個init消息給未初始化的actor,它包含你的構造函數參數。你的分片演員將有他們那種裏面的東西:

val par1: Option[param1Type] = None 

def receive = { 
    case init(par1value) => par1 = Some(par1value) 
    case query(par1) => sender ! par1 
} 

而且從您所在地區訪問的演員你總是可以先發送查詢消息,然後在init消息,如果回報是無。這假設你的區域訪問actor不需要獲得初始化actor的列表,在這種情況下,你可以使用init產生並正常使用它們。 好處是 一)它的優雅 b)有「感覺」的權利

壞處:1)它需要2個消息(如果你不保持初始化角色名單)

選項3)該選項已經過測試,不起作用。我會把它留在這裏讓人們避免浪費時間去嘗試。 我不知道這是否正常工作,我沒有測試過,因爲我在生產中使用這個場景時有特殊的約束,花式的東西是不允許的^ _ ^但是請隨時嘗試,請讓我知道下午或評論! 基本上,你

val counterRegion: ActorRef = ClusterSharding(system).start(
    typeName = "Counter", 
    entryProps = Some(Props[Counter]), 
    idExtractor = idExtractor, 
    shardResolver = shardResolver) 

啓動區如果你在你的地區創造的演員,做這樣的事情:

var providedPar1 = v1 
def providePar1 = providedPar1 

val counterRegion: ActorRef = ClusterSharding(system).start(
    typeName = "Counter", 
    entryProps = Some(Props(classOf[Counter], providePar1), 
    idExtractor = idExtractor, 
    shardResolver = shardResolver) 

然後你改變providedPar1的每一個創造價值?這樣做的缺點是,在它的選項中,你需要避免改變providePar1的值,直到你100%確定這個actor已經被創建,否則你可能冒險訪問新的錯誤值(yay ,競賽條件!)

一般來說,使用選項2 imho會更好,但在大多數情況下,由1引入的風險很小,您可以根據簡單性(和性能)的優勢正確地減輕風險。

希望這個咆哮有幫助,讓我知道,如果你嘗試3它是如何工作的!

+1

感謝您的想法。作爲我們僅暗示的問題的第一部分的直接答案,ClusterSharding沒有內置的方式來支持動態道具。因此,將您的答案描述爲與我的後續問題「這是我的最佳選擇?」有關嗎?我相信你的回答很好。 – Rich 2014-10-23 19:00:57

+0

是的,我不確定是最好將它完全移除還是將它標記爲非工作狀態,這樣也許有人會在akka上撿起它* wink wink *(或者至少人們會知道這不是一種選擇,並且不會浪費時間嘗試它)。另外,也許可以通過Guice獲得一些東西,然後入侵InjectedProps,我在某處看到過類似的東西,但不幸的是我不記得細節。 – 2014-10-24 19:29:07