2

If I had a RoundRobinPool like this

val actorPoolRef = AkkaConfig.actorSystem.actorOf(RoundRobinPool(100).props(Props[MyService]))

and a handler

def requestHandler(request: HttpRequest): Future[HttpResponse] = {
  val promise = Promise[HttpResponse]()
  promise.completeWith(actorPoolRef ? request)
  promise.future
}

Is there any way I can

  • get the exact actor reference from the scope of def requestHandler, or
  • send a follow-up message to the same actor that just handled the request
edg
  • 21
  • 2

1 Answers1

1

you can do by using the akka.pattern.ask to request the actor reference from a RoundRobinPool of actors, returning the self.path as an Option and wrapping the response as Option[ActorPath]. To clarify what I am saying I build this simple proof of concept:

import akka.actor.{Actor, ActorLogging, ActorPath, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.pattern.ask
import akka.routing.RoundRobinPool
import akka.util.Timeout

import scala.concurrent.Future
import scala.concurrent.duration._

object BasicRoundRobinHttpServer {
  def main(args: Array[String]): Unit = {
    run()
  }

  def run() = {
    implicit val system = ActorSystem("BasicRoundRobinHttpServer")
    import system.dispatcher
    implicit val timeout = Timeout(3 seconds)

    val myServiceActor = system.actorOf(RoundRobinPool(5).props(Props[MyService]), "myServiceActor")

    val simpleRoute: Route =
      (path("reference") & get) {
        val validResponseFuture: Option[Future[HttpResponse]] = {
          // construct the HTTP response
          val actorPathResponse: Future[Option[ActorPath]] = (myServiceActor ? "reference").mapTo[Option[ActorPath]]
          Option(actorPathResponse.map(ref => HttpResponse(
            StatusCodes.OK,
            entity = HttpEntity(
              ContentTypes.`text/html(UTF-8)`,
              s"""
                 |<html>
                 | <body>I got the actor reference: ${ref} </body>
                 |</html>
                 |""".stripMargin
            ))))
        }
        val entityFuture: Future[HttpResponse] = validResponseFuture.getOrElse(Future(HttpResponse(StatusCodes.BadRequest)))
        complete(entityFuture)
      }
    println("http GET localhost:8080/reference")
    Http().newServerAt("localhost", 8080).bind(simpleRoute)
  }
}

class MyService extends Actor with ActorLogging {
  override def receive: Receive = {
    case "reference" =>
      log.info(s"request reference at actor: ${self}")
      sender() ! Option(self.path)
    case message =>
      log.info(s"unknown message: ${message.toString}")
  }
}

requesting the address $ http GET localhost:8080/reference from the browser or using any HTTP requester several times you get actor reference $a, $b, etc...

// first time
<html>
 <body>I got the actor reference: Some(akka://BasicRoundRobinHttpServer/user/myServiceActor/$a) </body>
</html>
// second time
<html>
 <body>I got the actor reference: Some(akka://BasicRoundRobinHttpServer/user/myServiceActor/$b) </body>
</html>
...
Felipe
  • 7,013
  • 8
  • 44
  • 102