I am using akka-http, my build.sbt configuration is:
scalaVersion := "2.11.7"
libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-http-experimental_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-http-spray-json-experimental_2.11" % "2.4.2"
libraryDependencies += "com.typesafe.akka" % "akka-slf4j_2.11" % "2.4.2"
I am exposing a simple REST API with only one GET URL
foo is a function that returns a Future
implicit val actorSystem = ActorSystem("system", config)
implicit val actorMaterializer = ActorMaterializer()
val route: Route = {
get {
path("foo") {
complete { foo }
}
}
}
The web-service is expected to have a lot of calls, and I want to make the service redundant in case of failure, so I want to have two instances running simultaneously to handle all the requests.
The answer to this question demonstrates how to make an Actor call from within a Route
.
If you combine that technique with the clustering capabilities within Akka you should be able to get the job done.
Have your Route send a message to a Router
that will dispatch the message to 1 of N remotely deployed Actors (from your question it sounds like a round robin router is what you want).
class HttpResponseActor extends Actor {
def foo : HttpResponse = ??? // Not specified in question
override def receive = {
case _ : HttpRequest => foo
}
}
import akka.actor.{ Address, AddressFromURIString }
import akka.remote.routing.RemoteRouterConfig
val addresses = Seq(Address("akka.tcp", "remotesys", "otherhost", 1234),
AddressFromURIString("akka.tcp://othersys@anotherhost:1234"))
val routerRemote =
system.actorOf(RemoteRouterConfig(RoundRobinPool(5), addresses).props(Props[HttpResponseActor]))
The remote Actor responds with the HttpResponse. This Response can go through the Router or directly back to the Route.
The Route sticks the answer in a complete
Directive to return back to the client.
val route =
get {
path("foo") {
onComplete((routerRemote ? request).mapTo[HttpResponse]) {
case Success(response) => complete(response)
case Failure(ex) => complete((InternalServerError, s"Actor not playing nice: ${ex.getMessage}"))
}
}
}