2

원격 액터가 Bar이고 로컬 액터가 Foo입니다. CLI를 실행할 때마다 Foo을 사용하여 Bar에 메시지를 전달하고 싶습니다.Akka 리모팅을 사용하여 CLI를 통해 원격 액터에게 메시지를 보낼 수 있습니까?

Bar은 메시지를 성공적으로 전달할 수 있지만 메시지를 기다리는 동안 Foo은 중단됩니다. 이 문제를 해결하기 위해 Foo의 메인 끝에 sys.exit(0)을 추가했습니다. 이로 인해 Foo의 시스템과 연결 문제가 발생합니다.

로컬 액터를 수동으로 종료하지 않고 연속 CLI 발급간에 로컬 액터를 종료하려면 어떻게해야합니까?

코드를 종료하고 알려주세요!


푸 :

build.sbt

name := "Foo" 

version := "1.0" 

scalaVersion := "2.11.8" 

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.4.11" 
libraryDependencies += "com.typesafe.akka" %% "akka-remote" % "2.4.11" 
libraryDependencies += "com.github.scopt" %% "scopt" % "3.5.0" 

fork in run := true 

Main.scala

import akka.actor._ 
import com.typesafe.config.ConfigFactory 

case class Config(mode: String = "", greeting: String="") 

class Foo extends Actor { 
    // create the remote actor 
    val BarActor = context.actorSelection("akka.tcp://[email protected]:2552/user/BarActor") 

    def receive = { 
    case method: String => BarActor ! method 
    } 
} 

object CommandLineInterface { 

    val config = ConfigFactory.load() 
    val system = ActorSystem("FooSystem", config.getConfig("FooApp")) 

    val FooActor = system.actorOf(Props[Foo], name = "FooActor") 

    val parser = new scopt.OptionParser[Config]("Foo") { 
    head("foo", "1.x") 

    help("help").text("prints usage text") 

    opt[String]('m', "method").action((x, c) => 
     c.copy(greeting = x)).text("Bar will greet with <method>") 
    } 
} 

object Main extends App { 
    import CommandLineInterface.{parser, FooActor} 

    parser.parse(args, Config()) match { 
    case Some(config) => FooActor ! config.greeting 
    case None => sys.error("Bad news...") 
    } 
    /* 
    When sys.exit(0) commented, this hangs and Bar greet. 
    When sys.exit(0) uncommented, this doesn't hang, but also Bar doesn't greet. 
    */ 

    //sys.exit(0) 
} 
012,351,

application.conf

FooApp { 
    akka { 
    loglevel = "INFO" 
    actor { 
     provider = "akka.remote.RemoteActorRefProvider" 
    } 
    remote { 
     enabled-transports = ["akka.remote.netty.tcp"] 
     netty.tcp { 
     hostname = "127.0.0.1" 
     port = 0 
     } 
     log-sent-messages = on 
     log-received-messages = on 
    } 
    } 
} 

바 :

name := "Bar" 

version := "1.0" 

scalaVersion := "2.11.8" 

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.4.11" 
libraryDependencies += "com.typesafe.akka" %% "akka-remote" % "2.4.11" 
build.sbtMain.scala
import akka.actor._ 
import com.typesafe.config.ConfigFactory 

class Bar extends Actor { 
    def receive = { 
    case greeting: String => Bar.greet(greeting) 
    } 
} 

object Bar { 
    val config = ConfigFactory.load() 
    val system = ActorSystem("BarSystem", config.getConfig("BarApp")) 
    val BarActor = system.actorOf(Props[Bar], name = "BarActor") 

    def greet(greeting: String) = println(greeting) 

    def main(args: Array[String]): Unit = { 
    /* Intentionally empty */ 
    } 
} 

application.conf

BarApp { 
    akka { 
    loglevel = "INFO" 
    actor { 
     provider = remote 
    } 
    remote { 
     enabled-transports = ["akka.remote.netty.tcp"] 
     netty.tcp { 
     hostname = "127.0.0.1" 
     port = 2552 
     } 
     log-sent-messages = on 
     log-received-messages = on 
    } 
    } 
} 

sbt 'run-main Main -m hello'와 실행 Foosbt 'run-main Main'Bar를 실행합니다.

죄송합니다. 긴 코드는 사용하지만 내 문제는 MVCE입니다.

원하는 동작을 얻으려면 어떻게해야합니까? 원격 액터가 새 메시지를 기다리는 동안 CLI 액터가 연속 CLI 호출 사이에 없어집니다.

+1

가 왜'Bar'가 죽었다는 것을 생각합니까? 이것을 나타내는 로그에 뭔가가 있습니까? –

+0

@ PawełBartkiewicz 나는 내 의미를 정리하려고 노력했다. 미스 피크를 유감스럽게 생각합니다. :) 바라건대 그것은 더 분명하다. – erip

답변

3

당신이 FooActor에 메시지를 전송 한 후 즉시 sys.exit(0)를 호출하기 때문에이 일어나고, 그래서 FooActor 전에 응용 프로그램이 종료가 BarActor에 앞으로 말할 것도없고, 심지어 메시지를 읽을 수있는 기회를 얻을 수있는 중요한 기회가있다.

이되고 그들 중 many possible solutions, 하나가 될 것 같다 :

class Foo extends Actor { 
    // create the remote actor 
    val BarActor = context.actorSelection("akka.tcp://[email protected]:2552/user/BarActor") 

    override def receive = { 
    case method: String => { 
     BarActor ! method 
     self ! PoisonPill 
    } 
    } 

    override def postStop = { 
    context.system.terminate 
    } 
} 

불행하게도, 여전히 시스템이 Bar에 메시지를 발송하기 전에 종료됩니다 것으로 나타났다.

"화재 및 잊어"스타일로 메시지를 보내려는 경우이 문제에 대한 합리적인 해결책을 찾을 수 없습니다. 그러나 대부분의 경우, 그것은 원격 배우에서 몇 가지 종류의 응답을 얻기 위해 바람직한, 그래서 당신은 할 수 :

class Foo extends Actor { 
    // create the remote actor 
    val BarActor = context.actorSelection("akka.tcp://[email protected]:2552/user/BarActor") 

    override def receive = { 
    case method: String => { 
     BarActor ! method 
     context.become(waitingToKillMyself) 
    } 
    } 

    def waitingToKillMyself: Receive = { 
    case response: String => { 
     println(response) 
     self ! PoisonPill 
    } 
    } 

    override def postStop = { 
    context.system.terminate 
    } 
} 

// ... 

object Main extends App { 
    import CommandLineInterface.{parser, FooActor, system} 
    import system.dispatcher 

    parser.parse(args, Config()) match { 
    case Some(config) => { 
     FooActor ! config.greeting 
     system.scheduler.scheduleOnce(10.seconds, FooActor, PoisonPill) 
    } 

    case None => sys.error("Bad news...") 
    } 
} 

바 :

class Bar extends Actor { 
    def receive = { 
    case greeting: String => { 
     Bar.greet(greeting) 
     sender() ! "OK" 
    } 
    } 
} 
+0

이것은 일회성 메시지 인 경우 단단한 솔루션처럼 보이지만 기본적으로 항상 'Bar'가 메시지를 기다리고 싶습니다. 이 목표를 달성 할 수 있을까요? – erip

+1

'BarSystem'은 별도의 액터 시스템이 아닙니까? –

+0

죄송합니다. 편집 후에 댓글을 보지 못했습니다. 네,이게 잘 작동한다고 믿습니다. (지금 당장은 이것을 시도 할 수 없습니다. 원한다면 나중에 할 수 있습니다.) 'FooSystem'과'BarSystem'은 별도의 액터 시스템이기 때문에'shutdown' 또는'terminate'는'FooSystem' 만 멈추어야합니다 ([documentation] (http://doc.akka.io/api/akka/2.4/index.html). #[email protected]() : scala.concurrent.Future [akka.actor.Terminated])). –