scala - 根据请求模式创建子actor
问题描述
我正在尝试使用 Play Framework 创建一个 Web 套接字服务器,其中来自服务器的响应应该是基于请求的同步或异步的。
请求将在 Parent Actor 中处理。根据请求中的动作,将创建子 Actor,并将消息传递给子 Actor 进行处理,并将响应发送回控制器。
有预定义的动作和一些动作的示例请求如下,[,,]
["1234","启动","{"system":"ABCD"}"]
["5678","开始","{"system":"EFGH", "currenTime":"1559548762638"}"]
@Singleton
class RequestController @Inject()(cc: ControllerComponents)(implicit system: ActorSystem, mat: Materializer) extends AbstractController(cc) {
def ws = WebSocket.accept[String, String] {req =>
ActorFlow.actorRef { out =>
ParentActor.props(out)
}
}
}
object ParentActor {
def props(out: ActorRef) = Props(new ParentActor(out))
}
class ParentActor(out : ActorRef) extends Actor {
override def receive: Receive = {
case msg: String =>
//String split opeartion to find the action.
//create child actor for the action and pass the message to the child actor
val action = msg.split(",")[2]
if("Boot".equals(action)){
val bootActor: ActorRef = actorSystem.actorOf(Props[BootActor])
childActor ! msg
}else if("Start".equals(action)){
val startActor: ActorRef = actorSystem.actorOf(Props[StartActor])
startActor ! msg
}
case msg: Response => out ! msg
}
}
case class Response(name:String, msg:String)
class BootActor extends Actor{
override def receive: Receive = {
case msg : String =>
sender() ! Response("ABC",msg)
}
}
class StartActor extends Actor{
override def receive: Receive = {
case msg : String =>
sender() ! Response("Efgh",msg)
}
}
现在我正在从请求中获取操作并为该操作创建一个子角色并将消息传递给子角色进行处理。但我不确定是否有更好的方法或设计模式来处理请求并创建子角色而不是字符串操作?
解决方案
首先,您的代码中似乎有一个错字:
if ("Boot".equals(action)) {
val bootActor: ActorRef = actorSystem.actorOf(Props[BootActor])
childActor ! msg
} else if ("Start".equals(action)) {
val startActor: ActorRef = actorSystem.actorOf(Props[StartActor])
startActor ! msg
}
第一个条件子句中的消息应该发送到bootActor
而不是childActor
,这在您的代码片段中是未定义的。
另一个问题是您正在使用actorSystem.actorOf
创建子演员。此方法创建“顶级”演员,应将其保持在最低限度。与创建的演员在监护演员actorSystem.actorOf
的监督下。这与您的代码有关的意思是,当停止时(即,当 WebSocket 关闭时,Play 停止使用的参与者,如此处所述),并且不会停止的多个实例,给您留下一堆闲置的顶级演员。补救措施是使用创建and的实例:这样做会使这些实例成为.ParentActor
ActorFlow
BootActor
StartActor
context.actorOf
BootActor
StartActor
ParentActor
此外,您应该使用==
运算符而不是equals
方法。
以下是上述更改:
if ("Boot" == action) {
val bootActor: ActorRef = context.actorOf(Props[BootActor])
bootActor ! msg
} else if ("Start" == action) {
val startActor: ActorRef = context.actorOf(Props[StartActor])
startActor ! msg
}
上面可以稍微简化为以下内容:
val childActor =
if (action == "Boot") context.actorOf(Props[BootActor])
else context.actorOf(Props[StartActor])
childActor ! msg
为了进一步简化您的代码,不要创建子角色,在这种情况下这不是必需的。将与actor交互的所有逻辑移动out
到单个actor中。
推荐阅读
- c# - 为什么同步方法的异步对应物的吞吐量较小?
- python-3.x - discord.py on_member_update 活动时间
- javascript - quick.db 库存系统
- python - cv2.drawContours 不显示所有轮廓
- python - 在python中保存预测图像使其更暗
- node.js - GAE Flex Price 作为 WebSocket 服务器
- javascript - 如何使用 JS 将文件夹中的文件内容附加到 HTML?
- elasticsearch - 如何像其他搜索引擎一样在弹性搜索 DSL 查询中省略类似的结果?
- windows - 如何使 Inno Setup 在开始菜单中创建单个快捷方式/图标而不是文件夹(程序组)
- r - 在r中绘制vline图highcharts