gpt4 book ai didi

scala - 通过 ID 获取或创建子 Actor

转载 作者:行者123 更新时间:2023-12-02 06:54:45 25 4
gpt4 key购买 nike

我的系统中有两个 Actor 。谈话者和谈话。对话由两个谈话者组成(到目前为止)。当一个 Talker 想要加入对话时,我应该检查对话是否存在(另一个 talker 创建了它),如果不存在,则创建它。我的 Talker Actor 的方法中有这段代码:

  def getOrCreateConversation(conversationId: UUID): ActorRef = {

// @TODO try to get conversation actor by conversationId
context.actorSelection("user/conversation/" + conversationId.toString)

// @TODO if it not exists... create it
context.actorOf(Conversation.props(conversationId), conversationId.toString)
}

如您所见,当我使用 actorOf 创建我的 session actor 时,我将 conversationId 作为第二个参数传递。我这样做是为了方便搜索这个 Actor ...这是正确的方法吗?

谢谢

已编辑

感谢@Arne,我终于做到了:

class ConversationRouter extends Actor with ActorLogging {
def receive = {
case ConversationEnv(conversationId, msg) =>
val conversation = findConversation(conversationId) match {
case None => createNewConversation(conversationId)
case Some(x) => x
}
conversation forward msg
}

def findConversation(conversationId: UUID): Option[ActorRef] = context.child(conversationId.toString)

def createNewConversation(conversationId: UUID): ActorRef = {
context.actorOf(Conversation.props(conversationId), conversationId.toString)
}
}

和测试:

class ConversationRouterSpec extends ChatUnitTestCase("ConversationRouterSpec") {

trait ConversationRouterSpecHelper {
val conversationId = UUID.randomUUID()

var newConversationCreated = false

def conversationRouterWithConversation(existingConversation: Option[ActorRef]) = {
val conversationRouterRef = TestActorRef(new ConversationRouter {
override def findConversation(conversationId: UUID) = existingConversation

override def createNewConversation(conversationId: UUID) = {
newConversationCreated = true
TestProbe().ref
}
})
conversationRouterRef
}
}

"ConversationRouter" should {
"create a new conversation when a talker join it" in new ConversationRouterSpecHelper {
val nonExistingConversationOption = None
val conversationRouterRef = conversationRouterWithConversation(nonExistingConversationOption)

conversationRouterRef ! ConversationEnv(conversationId, Join(conversationId))

newConversationCreated should be(right = true)
}

"not create a new conversation if it already exists" in new ConversationRouterSpecHelper {
val existingConversation = Option(TestProbe().ref)
val conversationRouterRef = conversationRouterWithConversation(existingConversation)

conversationRouterRef ! ConversationEnv(conversationId, Join(conversationId))

newConversationCreated should be(right = false)
}
}
}

最佳答案

确定 Actor 的存在不能同步完成。所以你有几个选择。前两个在本质上更具概念性,用于说明执行异步查找,但我提供它们更多是为了引用有关参与者的异步性质。第三种可能是正确的做事方式:

<强>1。使函数返回一个 Future[ActorRef]

def getOrCreateConversation(conversationId: UUID): Unit {
context.actorSelection(s"user/conversation/$conversationId")
.resolveOne()
.recover { case _:Exception =>
context.actorOf(Conversation.props(conversationId),conversationId.toString)
}
}

<强>2。使其成为 Unit 并将 ActorRef 发送回您当前的 actor

与上面的几乎相同,但现在我们将 future 传回当前 actor,以便可以在调用 actor 的 receive 循环的上下文中处理已解析的 actor:

def getOrCreateConversation(conversationId: UUID): Unit {
context.actorSelection(s"user/conversation/$conversationId")
.resolveOne()
.recover { case _:Exception =>
context.actorOf(Conversation.props(conversationId),conversationId.toString)
}.pipeTo(self)
}

<强>3。创建一个路由器 actor,您将 Id 的消息发送到该路由器 actor,它会创建/解析子节点并转发消息

我说这可能是正确的方法,因为您的目标似乎是在特定的命名路径上进行廉价查找。您给出的示例假设该函数总是从路径 /user/conversation 的参与者内部调用,否则 context.actorOf 不会在 处创建子项>/user/conversation/{id}/.

也就是说,您手上有一个路由器模式,并且您创建的子节点在其子集合中已经为路由器所知。此模式假定您在任何对话消息周围都有一个信封,如下所示:

case class ConversationEnv(id: UUID, msg: Any)

现在所有对话消息都被发送到路由器,而不是直接发送到对话子。路由器现在可以在其子集合中查找子集合:

def receive = {
case ConversationEnv(id,msg) =>
val conversation = context.child(id.toString) match {
case None => context.actorOf(Conversation.props(id),id.toString)
case Some(x) => x
}
conversation forward msg
}

额外的好处是你的路由器也是 session 监督者,所以如果 session 子死了,它可以处理它。不将子 ActorRef 暴露给外界还有一个好处,即您可以让它在空闲时死掉,并在下一个消息接收时重新创建它,等等。

关于scala - 通过 ID 获取或创建子 Actor ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33830223/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com