根据请求模式创建子actor

时间:2019-06-03 09:50:18

标签: scala websocket playframework akka

我正在尝试使用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操作?

1 个答案:

答案 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所述), BootActorStartActor的实例将不会被停止,从而使您剩下一堆闲置的顶级参与者。补救措施是使用context.actorOf创建BootActorStartActor的实例:这样做使这些实例成为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角色进行交互的所有逻辑移到单个角色中。