每个请求的Akka HTTP"演员"图案

时间:2016-04-12 14:59:47

标签: akka reactive-programming spray akka-http

目前我正在尝试在Akka HTTP中实施"actor-per-request" pattern proposed by NET-A-PORTER devs。我面临的问题是这种模式没有记录在文档的任何地方。似乎没有办法做到以下几点:

IO(Http) ! Http.Bind(serviceActor, "localhost", port = 38080)

如何在不使用Spray的情况下为每个请求使用一个Akka演员?

1 个答案:

答案 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)