目前我正在尝试在Akka HTTP中实施"actor-per-request" pattern proposed by NET-A-PORTER devs。我面临的问题是这种模式没有记录在文档的任何地方。似乎没有办法做到以下几点:
IO(Http) ! Http.Bind(serviceActor, "localhost", port = 38080)
如何在不使用Spray的情况下为每个请求使用一个Akka演员?
答案 0 :(得分:0)
HttpExt
类有一个可用于此目的的方法bindAndHAndleAsync
。此方法采用具有以下签名的函数:
handler: (HttpRequest) ⇒ Future[HttpResponse]
所以,假设我们有一个演员在被问及HttpResponse
时会产生HttpRequest
:
class HttpResponseHandlerActor extends Actor {
override def receive = {
case _ : HttpRequest =>
sender() ! HttpResponse(200, entity = "Response From Actor")
}
}
效率低下
你的问题明确询问如何为每个请求使用1个Actor,为此我们现在可以使用我们的Actor类来创建一个处理函数:
implicit val actorSystem = ActorSystem()
implicit val timeout = Timeout(5 seconds)
val handler : (HttpRequest) => Future[HttpResponse] = (httpRequest) = {
val actorHandlerRef =
system.actorOf(Props[HttpResponseHandlerActor], "responseActor")
(actorHandlerRef ask httpRequest).mapTo[HttpResponse]
}
我们现在可以使用此函数将我们的服务器绑定到:
val serverBinding : Future[ServerBinding] =
Http().bindAndHandleAsync(handler, "localhost", 8080)
高效答案
通常没有必要为每个请求重新创建一个新的Actor,通常你想要创建1个Actor并将其用于每个请求。
因此,我们可以将Actor创建移到handler
之外:
val handler : (ActorRef) => (HttpRequest) => Future[HttpResponse] =
(actorRef) => (httpRequest) =>
(actorRef ask httpRequest).mapTo[HttpResponse]
服务器绑定现在稍微修改为:
val singleResponseActorRef =
system.actorOf(Props[HttpResponseHandlerActor], "responseActor")
val serverBinding : Future[ServerBinding] =
Http().bindAndHandleAsync(handler(singleResponseActorRef),
"localhost",
8080)