2013-02-10 70 views
3

我在学习有关Akka 2.1中的远程演员,并试图修改counter example provided by Typesafe。 我从控制台实现了一个quick'n'dirty UI来发送滴答。并要求(并显示结果)当前计数退出。Akka 2.1远程:跨系统共享演员

这个想法是启动一个主节点,它将运行Counter actor和某个客户端节点,该节点将通过远程处理向其发送消息。不过,我想通过配置和代码的最小改变来实现这一点。所以通过改变配置可以使用本地角色。

我发现this blog entry关于类似的问题,即所有的API调用都需要经过一个actor,即使有很多实例在运行。

我写了类似的配置,但我不能让它工作。我当前的代码确实使用了远程处理,但是它为每个新节点在主节点上创建了一个新的actor,并且我无法在未明确给出路径(并且违反配置点)的情况下连接到现有的actor。然而这不是我想要的,因为这种方式不能在JVM之间共享状态。可through a git repo

完全可运行代码这是我的配置文件

akka { 
    actor { 
     provider = "akka.remote.RemoteActorRefProvider" 
     deployment { 
      /counter { 
       remote = "akka://[email protected]:2552" 
      } 
     } 
    } 
    remote { 
     transport = "akka.remote.netty.NettyRemoteTransport" 
     log-sent-messages = on 
     netty { 
      hostname = "127.0.0.1" 
     } 
    } 
} 

和全源

import akka.actor._ 
import akka.pattern.ask 
import scala.concurrent.duration._ 
import akka.util.Timeout 
import scala.util._ 

case object Tick 
case object Get 

class Counter extends Actor { 
    var count = 0 

    val id = math.random.toString.substring(2) 
    println(s"\nmy name is $id\ni'm at ${self.path}\n") 
    def log(s: String) = println(s"$id: $s") 

    def receive = { 
    case Tick => 
     count += 1 
     log(s"got a tick, now at $count") 
    case Get => 
     sender ! count 
     log(s"asked for count, replied with $count") 
    } 
} 

object AkkaProjectInScala extends App { 
    val system = ActorSystem("ticker") 
    implicit val ec = system.dispatcher 

    val counter = system.actorOf(Props[Counter], "counter") 

    def step { 
    print("tick or quit? ") 
    readLine() match { 
     case "tick" => counter ! Tick 
     case "quit" => return 
     case _ => 
    } 
    step 
    } 
    step 

    implicit val timeout = Timeout(5.seconds) 

    val f = counter ? Get 
    f onComplete { 
    case Failure(e) => throw e 
    case Success(count) => println("Count is " + count) 
    } 

    system.shutdown() 
} 

我用sbt run而在另一个窗口sbt run -Dakka.remote.netty.port=0运行它。

回答

0

我试过你的git项目,它实际上工作正常,除了编译错误,并且你必须启动sbt会话-Dakka.remote.netty.port=0参数给jvm,而不是run的参数。

你也应该明白,你不必在两个进程中启动Counter actor。在此示例中,它旨在从客户端创建并部署在服务器上(端口2552)。您不必在服务器上启动它。在这个例子中,在服务器上创建角色系统应该足够了。

+0

修复了代码。更改参数不会改变行为。它有效,但不是我想要的方式。为了重述我的问题:如何(如果可能)配置akka不是为每个客户创建新的演员,而是分享现有的演员? – edofic 2013-02-11 11:11:50

1

我发现我可以使用某种模式。 Akka远程只允许在远程系统上部署(无法通过配置找到远程查看的方式,但我误以为是这样?)。

所以我可以部署一个能够传回ActorRef的“侦察兵”。在“scout-hack”分支下的原始回购中可运行的代码。因为这感觉像一个黑客。我仍然会欣赏基于配置的解决方案。

演员

case object Fetch 

class Scout extends Actor{ 
    def receive = { 
    case Fetch => sender ! AkkaProjectInScala._counter 
    } 
} 

计数器演员创造是现在懒

lazy val _counter = system.actorOf(Props[Counter], "counter") 

所以只执行对主(由端口来确定),并可以获取这样

val counter: ActorRef = { 
    val scout = system.actorOf(Props[Scout], "scout") 
    val ref = Await.result(scout ? Fetch, timeout.duration) match { 
    case r: ActorRef => r 
    } 
    scout ! PoisonPill 
    ref 
} 

And full config

akka { 
    actor { 
     provider = "akka.remote.RemoteActorRefProvider" 
     deployment { 
      /scout { 
       remote = "akka://[email protected]:2552" 
      } 
     } 
    } 
    remote { 
     transport = "akka.remote.netty.NettyRemoteTransport" 
     log-sent-messages = on 
     netty { 
      hostname = "127.0.0.1" 
     } 
    } 
} 

编辑:我还发现了一个清洁的方式:检查“counterPath”anf的配置,如果存在actorFor(path)else create actor。很不错,你可以在运行时注入主人,代码比“侦察员”更清洁,但它仍然需要决定查找天气或创建演员。我想这是无法避免的。