2014-11-21 63 views
1

在調用rest api時,我想將actor的路由切換到另一個路由。 請參閱下面的代碼。Akka Actor hotswapping using rest api

幾個問題:

  1. 代碼編譯罰款,但是當應用程序被啓動,一個HTTP調用時,我得到配置的1註冊超時第二期滿,停止的消息,我不得到任何迴應服務器。
  2. 我希望能夠通過api將路由切換到另一組路由。

取得

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

} 
+0

我不看到一個明顯的問題。您收到的錯誤消息似乎表明您的演員出於某種原因未處理「已連接」消息。 – jrudolph 2014-11-21 07:57:48

+0

如果我將接收方法更改爲def receive = runRoute(myRoute),則服務器響應沒有任何問題。 – Phani 2014-11-23 01:42:41

+0

是的,另一個答案解釋了原因:您需要通過路由傳遞實際消息。 – jrudolph 2014-11-24 07:16:33

回答

2

runRoute是部分功能,所以你不能只是寫runRoute(routeName)稱呼它 - 它只是返回的功能(它處理的路線),但沒有調用它;你應該明確地傳遞請求對象:

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)收益函數處理「已連接」的消息。所以這就是爲什麼你會得到「註冊超時」錯誤 - 你不會從接收方法返回這個函數。當你寫def receive = runRoute(route)這個函數被用作處理程序,一切都很好。但是當你寫def receive = {case _ => runRoute(route)}什麼也沒有發生 - receive函數什麼都不做,因爲runRoute(route)返回的函數無處可去。

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

,你也可以打電話從您的路徑成爲/ unbecome正確的,因爲你已經有MyServiceActor自我型。當您使用單獨的Swap消息 - 演員可以改變其角色後,你一點點收到成功的「交換」響應(角色改變將會異步發生)

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

更新:你的路徑的匹配也是不正確。用途:

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

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

Updated2:

確保您男主角註冊單身您主營:

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

+0

我必須明確地傳遞默認值 runRoute(otherRoutes)(ExceptionHandler.default,RejectionHandler.Default,context, RoutingSettings.default,LoggingContext.fromActorRefFactory)(x) – Phani 2014-11-23 16:47:56

+0

我第一次碰到swap之後預期的「http:// localhost:8080/swap「將使用otherRoutes,但myRoute將繼續使用,並在瀏覽器上顯示」MyRoute「。我在這裏錯過了什麼? – Phani 2014-11-23 16:59:50

+0

關於implicits:你可以做'val f = runRoute(otherRoutes); f(x)'代替 – dk14 2014-11-24 00:13:10