2016-12-18 24 views
2

Я довольно новичок в мире Akka, и мне нужно перенести проект с Spray на akka-http.Заполнение запроса за пределами основного контроллера в Akka-http

В аэрозоле маршрут был типа Route = RequestContext ⇒ Unit.
Но в akka-http, это тип Route = RequestContext ⇒ Future[RouteResult].

Так что в брызгах мы часто обрабатываем и выполняем наши запросы через цепочку Актеров (вне основного контроллера), используя только огонь и забываем, поэтому нам не нужно было «спрашивать», и производительность была великолепной , Теперь мы должны использовать «спросить» каждый раз, когда мы передаем запрос другому Актеру (исправьте меня, если я ошибаюсь)

Я много искал, и я нашел несколько вариантов, которые я не уверен если они полностью удовлетворяют меня (необходимость заполнить запрос у другого Актера без необходимости вернуть его обратно в контроллер). Так вот, где вы могли бы мне помочь :)

Вариант 1: Использование onSuccess/onComplete
ли с помощью этого заблокировать мой главный контроллер получать больше запросов?

Вариант 2: Использование Future с и использованием RouteResult.Complete

Я нашел следующий пример в How to complete a request in another actor when using akka-http:

import akka.actor.{ActorSystem, Actor, Props} 
import akka.pattern.ask 
import akka.stream.ActorMaterializer 
import akka.http.scaladsl.Http 
import akka.http.scaladsl.server.Directives._ 
import akka.http.scaladsl.server.{RequestContext, RouteResult} 
import scala.concurrent.Future 
import akka.http.scaladsl.model.HttpResponse 
import akka.util.Timeout 

class RequestActor extends Actor { 

    //business logic - returns empty HttpResponse 
    def handleRequestMessage(requestContext : RequestContext) = 
    RouteResult.Complete(new HttpResponse()) 

    override def receive = { 
    case reqContext : RequestContext => 
     sender ! handleRequestMessage(reqContext) 
    } 
}//end class RequestActor 

object RouteActorTest extends App { 
    implicit val as = ActorSystem("RouteActorTest") 
    implicit val timeout = new Timeout(1000) 

    val actorRef = as actorOf Props[RequestActor] 

    def handleRequest(reqContext : RequestContext) : Future[RouteResult] = 
    ask(actorRef,reqContext).mapTo[RouteResult]  

    val route = path("") { get(handleRequest) } 

    //rest of application... 

}//end object RouteActorTest 

Но это на самом деле проходит ответ обратно каждый раз, когда к предыдущему Актер (отправитель), пока не достигнет основного контроллера. Другое дело, об этом варианте является то, что в коде, он говорит:

/** 
* The result of handling a request. 
* 
* As a user you typically don't create RouteResult instances directly. 
* Instead, use the methods on the [[RequestContext]] to achieve the desired effect. 
*/ 

Так что я не уверен, если это рекомендуемый способ сделать это.

Я попытался использовать requestContext.complete() в другом актере, но он не работает (ошибка не была выбрана, просто не отправляет ответ) Кто-нибудь знает, что лучший способ реализовать предыдущую архитектуру мы имел?

Большое спасибо!

ответ

2

необходимость выполнения запроса в другой актер без необходимости вернуть его обратно в контроллер

Вам не нужно выполнить запрос на другого актера. Все, что вам нужно сделать, это для актера, который обрабатывает запрос на отправку обратно результат, и вы можете использовать complete сигнализировать завершение будущего:

case class MyRequest(data: Int) 
case class MyResult(data: Int) 

class RequestActor extends Actor { 
    override def receive: PartialFunction[Any, Unit] = { 
    case MyRequest(data) => sender ! MyResult(data + 1) 
    } 
} 

И маршрут:

get { 
    path("yuval") { 
    import scala.concurrent.ExecutionContext.Implicits.global 
    implicit val timeout = Timeout(5 seconds) 

    complete { 
     val result = (completionActor ? MyRequest(1)).mapTo[MyResult] 
     result.map(r => HttpResponse(StatusCodes.OK, entity = s"Result was ${r.data}")) 
    } 
    } 
} 

Если вы хотят обращаться к HANDCRAFT HttpResponse самостоятельно, вы всегда можете использовать context.complete:

get { 
    path("yuval") { 
    import scala.concurrent.ExecutionContext.Implicits.global 
    implicit val timeout = Timeout(5 seconds) 
    context => { 
     val result = (completionActor ? MyRequest(1)).mapTo[MyResult] 
     result.flatMap(r => context.complete(HttpResponse(StatusCodes.OK, entity = s"Result was ${r.data}"))) 
    } 
    } 
} 
+0

это не позволит мне изменить меня последний комментарий, так вот полный один: Но я хочу выполнить запрос в другом Актере.Моя просьба передается от контроллера к actor1 -> actor2 -> actor3 -> actor4. И используя «спросить» каждый раз, когда я передаю его следующему актеру, будет снижаться производительность, так как он должен будет передать ответ каждому актеру (actor4 -> actor3 -> actor2 -> actor1 -> controller). – sid802