Шаблон Akka HTTP "субъект на запрос"

В настоящее время я пытаюсь реализовать шаблон "субъект-на-запрос", предложенный разработчиками NET-A-PORTER в Akka HTTP. Проблема, с которой я сталкиваюсь, заключается в том, что этот шаблон не задокументирован нигде в документации. Кажется, нет способа сделать следующее:

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

Как я могу использовать одного актера Akka на запрос без использования Spray?

1 ответ

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)

Эффективный ответ

Обычно нет необходимости заново создавать нового субъекта для каждого запроса, обычно требуется создать 1 субъект и использовать его для каждого запроса.
Поэтому мы можем переместить создание Актера за пределы 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)
Другие вопросы по тегам