Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to complete a request in another actor when using akka-http

I am using akka-http 1.0 and I would like to use a route defined as

def route: Route = path("") {
  // start actor with requestContext
  // call requestContext.complete(...) in actor with the result
}

How do I accomplish this?

like image 475
John Pertoft Avatar asked Aug 14 '15 13:08

John Pertoft


People also ask

How does Akka HTTP work?

The Akka HTTP modules implement a full server- and client-side HTTP stack on top of akka-actor and akka-stream . A typical application does not sit on top of Akka HTTP. Instead, Akka HTTP makes it easier to build integration layers based on HTTP, and therefore stays on the sidelines.

How does Akka handle concurrency?

Akka ensures that each instance of an actor runs in its own lightweight thread and its messages are processed one at a time. If this is the case that AKKA actors processes its messages sequentially then how AKKA provides concurrency for a single Actor.

Does Akka HTTP use Netty?

Akka HTTP implements a full server stack for HTTP, including full HTTPS support, and has support for HTTP/2. The Akka HTTP server backend is the default in Play. You can also use the Netty backend if you choose.


1 Answers

Elaborating on @jrudolph's comment, the below code satisfies your requirements of dispatching RequestContext values to an Actor. Your question indicated that you wanted a new Actor for each request; however, the below code uses the same Actor for all requests which I think is a more efficient/likely use case. The Actor creation can always be moved inside handleRequest if needed.

First we need an Actor for processing a request to a response:

import akka.actor.Actor
import akka.http.scaladsl.server.{RequestContext, RouteResult}
import akka.http.scaladsl.model.HttpResponse

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

Now create a utility function for querying the Actor:

import akka.actor.ActorRef
import scala.concurrent.Future
import akka.pattern.ask

object RequestActor {
  val handleRequest : ActorRef => RequestContext => Future[RouteResult] =
    (actorRef) =>
      (requestContext) =>
        ask(actorRef,reqContext).mapTo[RouteResult]
}

And all that is left to do is wire everything together into a service:

import akka.actor.{ActorSystem, Props}
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives.{get,path}
import akka.util.Timeout

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

  val sendRequestToActor : RequestContext => Future[RouteResult] = 
    RequestActor handleRequest (as actorOf Props[RequestActor])      

  val route = path("")(get(sendRequestToActor))

  //rest of application...

}//end object RouteActorTest
like image 62
Ramón J Romero y Vigil Avatar answered Sep 19 '22 21:09

Ramón J Romero y Vigil