/ / Akka Schauspieler hotswapping mit Rest api - Scala, Akka, Spray, Hotswap

Akka Schauspieler HotSwapping mit Rest api - Scala, Akka, Spray, Hotswap

Wenn ich eine Ruhe-API anrufe, möchte ich die Route des Schauspielers auf andere Routen umschalten. Bitte beachten Sie den folgenden Code.

Ein paar Fragen:

  1. Der Code kompiliert gut, aber wenn die App gestartet wird und ein http-Aufruf gemacht wird, bekomme ich eine konfigurierte Registrierung Timeout von 1 Sekunde abgelaufen, stoppe Nachricht und ich bekomme keine Antwort vom Server.
  2. Ich möchte in der Lage sein, Routing zu einem anderen Satz von Routen durch API zu wechseln.

gemacht

package com.example
import akka.actor.Actor
import akka.io.IO
import spray.httpx.RequestBuilding._
import spray.http.MediaTypes._
import spray.routing.{RoutingSettings, RejectionHandler, ExceptionHandler, HttpService}
import spray.util.LoggingContext
import scala.concurrent.Future
import spray.can.Http
import spray.http._
import akka.util.Timeout
import HttpMethods._
import akka.pattern.ask
import akka.event.Logging
import scala.concurrent.duration._

case object Swap
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {

implicit def actorRefFactory = context
import context._

def receive = {
case Swap =>
become {
case Swap => unbecome()
case _    => runRoute(otherRoutes)
}
case _ =>   runRoute(myRoute)
}
}


trait MyService extends HttpService { this: MyServiceActor =>

implicit val timeout: Timeout = Timeout(15.seconds)

implicit val system = context.system

val myRoute =
{
path("") {
get {
complete("MyRoute")
}
} ~ path("swap") {

get{
self ! Swap
complete("Swapped")
}
}
}

val otherRoutes =path("") {
get {
complete("OtherRoutes")
}
} ~ path("swap") {
get{
self ! Swap
complete("Reverted")
}
}

}

Antworten:

2 für die Antwort № 1

runRoute ist eine Teilfunktion, Sie können also nicht schreiben runRoute(routeName) um es aufzurufen - es wird nur die Funktion zurückgeben (die Routen behandelt), aber ohne sie aufzurufen; Sie sollten das Anfrageobjekt explizit übergeben:

def receive = {
case Swap =>
become {
case Swap => unbecome()
case x    => val f = runRoute(otherRoutes); f(x)
}
case x => val f = runRoute(myRoute); f(x)
}

runRoute(route) gibt eine Funktion zurück, die die Nachricht "Verbunden" handhabt. Das ist der Grund, warum Sie "Registrierungs-Timeout" -Fehler bekommen - Sie geben diese Funktion nicht von der Empfangs-Methode zurück. Wenn Sie schreiben def receive = runRoute(route) Diese Funktion wird als Handler verwendet und alles ist in Ordnung. Aber wenn du schreibst def receive = {case _ => runRoute(route)} nichts passiert - receive Funktion tue nichts, weil Funktion von zurückgegeben wird runRoute(route) geht nirgendwohin.

Sehen, https://github.com/spray/spray/blob/master/spray-routing/src/main/scala/spray/routing/HttpService.scala

Und Sie können auch direkt von Ihrer Route aus "becoming / uncome" aufrufen, da Sie MyServiceActor bereits als Selbst-Typ haben. Wenn Sie separat verwenden Swap Nachricht - Der Akteur kann seine Rolle ein wenig ändern, nachdem Sie eine erfolgreiche "Swapped" -Antwort erhalten haben (die Rollenänderung erfolgt asynchron)

case object Swap
class MyServiceActor extends Actor with MyService with akka.actor.ActorLogging {

implicit def actorRefFactory = context
import context._

def swapped = {
case x => val f = runRoute(otherRoutes); f(x)
}

def receive = {
case x => val f = runRoute(myRoute); f(x)
}
}


trait MyService extends HttpService { this: MyServiceActor =>

implicit val timeout: Timeout = Timeout(15.seconds)

implicit val system = context.system

val myRoute = {
pathSingleSlash {
get {
complete("MyRoute")
}
} ~ path("swap") {
get {
become(swapped)
complete("Swapped")
}
}
}

val otherRoutes = {
pathSingleSlash {
get {
complete("OtherRoutes")
}
} ~ path("swap") {
get{
unbecome()
complete("Reverted")
}
}
}
}

Aktualisiert: Deine Pfad-Matching ist ebenfalls falsch. Benutzen:

 pathSingleSlash {
...
} ~ path("swap") {
...
}

oder

 path("swap") {
...
} ~ path("") { //matches everything else
...
}

Aktualisiert2:

Stelle sicher, dass dein Akteur in deinem Main als Singleton registriert ist:

import akka.io.IO
import spray.can.Http

implicit val system = ActorSystem()

val myListener: ActorRef = Props[MyServiceActor]

IO(Http) ! Http.Bind(myListener, interface = "localhost", port = 8080)

http://spray.io/documentation/1.1-SNAPSHOT/spray-can/http-server/#http-server