我正在尝试使用Play Framework创建Web套接字服务器,其中服务器的响应应根据请求是同步还是异步。
请求将在父actor中进行处理。基于请求中的操作,将创建子actor,并将消息传递给子actor进行处理并将响应发送回控制器。
有预定义的操作,一些操作的示例请求如下, [,,
[“ 1234”,“启动”,“ {”系统“:” ABCD“}”]
[“ 5678”,“开始”,“ {”系统“:” 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)
}
}
现在,我正在从请求中获取动作,并为该动作创建子角色,并将消息传递给子角色进行处理。 但是我不确定是否有更好的方法或设计模式来处理请求并创建子actor而不是String操作?
答案 0 :(得分:1)
首先,您的代码中似乎有一个错字:
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
创建的演员在guardian actor的监督下。与您的代码有关,这意味着当ParentActor
停止时(即,当WebSocket关闭时,Play停止ActorFlow
中使用的actor,如here所述), 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
角色进行交互的所有逻辑移到单个角色中。