/ / Akka Aktor na hotswappingu wykorzystujący api - scala, akka, spray, hotswap

Akka Aktor na gorąco wykorzystujący aps - scala, akka, spray, hotswap

Po wywołaniu api odpoczynku, chciałbym zmienić routing aktora na inne trasy. Zobacz poniższy kod.

Kilka pytań:

  1. Kod kompiluje się dobrze, ale gdy aplikacja jest uruchomiona i wywoływane jest połączenie http, otrzymuję skonfigurowany limit czasu rejestracji wynoszący 1 sekundę, wiadomość zatrzymania się i nie otrzymuję żadnej odpowiedzi od serwera.
  2. Chcę mieć możliwość przełączania routingu na inny zestaw tras za pośrednictwem interfejsu API.

zrobiony

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

}

Odpowiedzi:

2 dla odpowiedzi № 1

runRoute jest funkcją częściową, więc nie możesz po prostu pisać runRoute(routeName) nazywać to - po prostu zwróci funkcję (która obsługuje trasy), ale bez wywoływania; należy jawnie przekazać obiekt żądania:

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) zwraca funkcję, która obsługuje komunikat "Połączono". Dlatego właśnie pojawia się błąd "timeout rejestracji" - nie zwracasz tej funkcji z metody receive. def receive = runRoute(route) ta funkcja jest używana jako przewodnik i wszystko jest w porządku. Ale kiedy piszesz def receive = {case _ => runRoute(route)} nic się nie dzieje - receive funkcja nic nie robi, ponieważ funkcja zwracana przez runRoute(route) nigdzie nie idzie.

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

Możesz również wywoływać status "stać się / nie" bezpośrednio z trasy, ponieważ masz już MyServiceActor jako własny typ. Kiedy używasz osobnego Swap wiadomość - aktor może nieco zmienić swoją rolę po otrzymaniu pomyślnej odpowiedzi "Zamiana" (zmiana roli nastąpi asynchronicznie)

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

Zaktualizowano: twoje matujące ścieżki są również niepoprawne. Posługiwać się:

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

lub

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

Zaktualizowano2:

Upewnij się, że twój aktor jest zarejestrowany jako singleton w twoim Main:

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