2014-10-20 65 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