관리 메뉴

HAMA 블로그

[Play2] 외부의 원격액터와 통신 본문

PlayFramework2

[Play2] 외부의 원격액터와 통신

[하마] 이승현 (wowlsh93@gmail.com) 2016. 10. 11. 21:30



Play2 - 리모트 액터와 통신



개념 


 사물인터넷  서비스를 생각해보자.  브라우저나 스마트폰을 통해 웹서비스에  명령을 전달하여  전등이 꺼지는 서비스이다. 웹서비스는 명령을 전달 받아서 외부 미들웨어에 전달해야할 것이다. 이때 외부 미들웨어는 아카리모트로 되어 있다고 하자.  Play2 는 내부에 아카시스템이 있는데 이 걸 사용할 순 없고 또 다른 하나의 아카리모트 시스템을 만들어서 외부의 아카리모트와 통신하도록 하는 전략을 세워본다.


설정 


 
먼저 아카 시스템을 설정한다. 또하나의 conf 파일을 만들어서 아래와 같이 remote provider 와 접속 대상의 패스를 설정한다. 
include "common"

Provider {
akka {
loglevel = "DEBUG"
loggers = ["akka.event.slf4j.Slf4jLogger"]
actor {
provider = "akka.remote.RemoteActorRefProvider"

default-dispatcher {
}
}

remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "127.0.0.1"
port = 24567
}

log-sent-messages = on
log-received-messages = on
}
}

}


RelayPath = "akka.tcp://relayRemote@192.168.1.148:24321/user/relay"


컨트롤러

package controllers
import play.api.mvc._
import akka.actor._
import javax.inject._

import play.api.inject.ApplicationLifecycle
import play.api.libs.concurrent.Execution.Implicits.defaultContext

import scala.concurrent.duration._
import services.TalkToRelay
import services.Runner


import scala.concurrent.Future

@Singleton
class ConfigurationCtrl @Inject()(lifecycle: ApplicationLifecycle) extends Controller {

lazy val ttr = new TalkToRelay()

lifecycle.addStopHook { () =>
Future.successful(ttr.terminate())
}

def setDataStorage(ip: String) = Action {
println("....................... setDataStorage.................")
ttr.sendDataStorageIP(ip)
Ok("OK")
}
}
 서비스 객체를 만들고 플레이가 죽을때 원격시스템도 종료시키기 위해서 라이프싸이클 설정을 해줬다.
 지금은  tell 패턴을 사용했지만 ask 패턴을 사용한다면 리턴값을 Future 로 받을 수 있을 것이다.


서비스  


val config = ConfigFactory.load("remoteProvider")
val remoteSystem = ActorSystem("seiws", config.getConfig("Provider"))
val runner = remoteSystem.actorOf(Props[Runner], "runner")


def sendDataStorageIP(ip : String) = {
Logger.info("....................... remotingSystem start .................")
runner ! ip
}

def terminate() = {
remoteSystem.terminate()
Logger.info("....................... remotingSystem terminated .................")

}
}

 설정파일로 부터 설정을 가지고 와서 우리 자신만의 아카 시스템을 생성했다.

액터
val path =  ConfigFactory.load("remoteProvider").getString("RelayPath")
val remoteActor = context.actorSelection(path)


context.setReceiveTimeout(3.seconds)
sendIdentifyRequest()

def sendIdentifyRequest(): Unit =
remoteActor ! Identify(path)

def receive = identifying


def identifying: Receive = {
case ActorIdentity(`path`, Some(actor)) =>
context.watch(actor)
context.become(active(actor))
context.setReceiveTimeout(Duration.Undefined)

case ActorIdentity(`path`, None) => Logger.info(s"Remote actor not available: $path")
case ReceiveTimeout => Logger.info(s"ReceiveTimeout"); sendIdentifyRequest()
}

def active(actor: ActorRef): Receive = {
case msg : String =>
Logger.info("send a msg to remote actor ")
remoteActor ! msg
case "Shutdown" => remoteActor ! Shutdown
case _ => Logger.info(" receive a invalid msg ")
}

설정파일로 부터 원격액터 경로를 가지고서 액터 셀렉션을 통해 액터 참조를 구해서 통신한다. 
초기에 원격노드가 살아있는지 체킹 (예제에서는 3초) 하는 과정을 거치고 있다. 원격노드가 살아 있다면 identifying 에서  active 로 상태변경을 하고 메세지 처리를 한다.

'PlayFramework2' 카테고리의 다른 글

[Play2] ScalaAsync (번역)  (0) 2016.10.14
[Play2] WebSockets  (0) 2016.10.13
[Play2] WS API (번역)  (0) 2016.10.11
[Play2] 마이크로서비스 (microservices)  (0) 2016.10.11
[Play2] Akka 의 결합 - (번역)  (0) 2016.10.10
Comments