Шаблон 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)