2016-12-18 1 views
2

Je suis assez nouveau dans le monde Akka et je dois migrer un projet de Spray à Akka-http.En complétant une demande en dehors du contrôleur principal dans Akka-http

En pulvérisation, une route était de type Route = RequestContext ⇒ Unit. Mais dans akka-http, il s'agit du type Route = RequestContext ⇒ Future[RouteResult]. Donc, en pulvérisation, nous traitons et complétons souvent nos demandes à travers une chaîne d'acteurs (en dehors du contrôleur principal) en utilisant seulement le feu et l'oubli, donc nous n'avons pas eu à "demander" et la performance était excellente . Maintenant, nous devons utiliser "demander" chaque fois que nous passons la demande à un autre acteur (corrigez-moi si je me trompe)

J'ai beaucoup cherché et j'ai trouvé quelques options dont je ne suis pas sûr si elles me satisfont pleinement (nécessité de compléter une requête dans un autre acteur sans avoir à le renvoyer au contrôleur). C'est donc là que vous pourriez me aider :)

Option 1: Utilisation onSuccess/onComplete
N'utilisant ce bloc mon contrôleur principal de recevoir plus de demandes?

Option 2: Utilisation Future s et en utilisant RouteResult.Complete

J'ai trouvé l'exemple suivant à 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 

Mais cela passe effectivement la réponse à chaque fois de retour à la précédente Acteur (l'expéditeur) jusqu'à ce qu'il atteigne le contrôleur principal. Une autre chose au sujet de cette option est que dans le code, il est dit:

/** 
* 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. 
*/ 

Je ne suis pas sûr que ce soit une façon recommandée de le faire.

J'ai essayé d'utiliser requestContext.complete() dans un autre acteur mais cela ne fonctionne pas (aucune erreur n'est renvoyée, il n'envoie simplement pas de réponse) Est-ce que quelqu'un sait quel est le meilleur moyen de mettre en œuvre l'architecture précédente? avait?

Merci beaucoup!

Répondre

2

la nécessité de remplir une demande dans un autre acteur sans avoir besoin de le retourner en arrière au contrôleur

Vous n'êtes pas obligé de remplir la demande dans un autre acteur. Tout ce que vous devez faire est pour l'acteur qui gère la demande de renvoyer un résultat, et vous pouvez utiliser complete pour signaler l'achèvement de l'avenir:

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) 
    } 
} 

Et la route:

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}")) 
    } 
    } 
} 

Si vous veulent gérer à la handcraft HttpResponse vous, vous pouvez toujours utiliser 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

Cela me me incluez pas laisser un commentaire dernier alors voici le plein: Mais je veux compléter la demande dans un autre acteur.Ma requête est passée du contrôleur à l'acteur 1 -> acteur2 -> acteur3 -> acteur4. Et en utilisant "demander" chaque fois que je le passe à l'acteur suivant, diminuera les performances car il devra renvoyer la réponse à chaque acteur (acteur4 -> acteur3 -> acteur2 -> acteur1 -> contrôleur). – sid802