Akka 2.1 Remote: sharing an actor across systems

I am talking about remote actors in Akka 2.1, and I tried to adapt the counter example provided in the Types section . I have implemented a quick'n'dirty UI from the console to send ticks. And leave with a request (and showing the result) of the current account.

The idea is to start a node wizard which will start Counter Counter and some client node which will send messages to it via remote access. However, I would like to achieve this with customization and minimal code changes. Therefore, by changing the configuration, you can use local executors.

I found this blog post about a similar issue where it is necessary that all API calls go through a single actor even if there are many instances running.

I wrote a similar config, but I can't seem to get it to work. My current code does indeed use remote access, but it creates a new actor on the master for every new node, and I can't get it to connect to an existing actor without explicitly specifying its path (and ignoring the config point). However, this is not what I want, since the state cannot be shared between JVMs this way.

Full available code via git repo

This is my config file

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

      

And full source

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

      

I used sbt run

it in another window sbt run -Dakka.remote.netty.port=0

to launch it as well.

+3


source to share


2 answers


I found out that I can use some kind of sample. Remote Akka only allows deployment to remote systems (Can't find a way to have it look at remote only via config .. am I wrong here?).

So I can deploy a "scout" that will return an ActorRef. The managed code is available in the source repo under the "scout-hack" branch. Because it looks like a hack. I will still be grateful for a configuration based solution.

Actor

case object Fetch

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

      

Counter-actor creation is now lazy

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

      



So it only runs on the host (determined by the port) and can be selected that way

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 configuration

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

      

EDIT : I also found a clean way: check the config for "counterPath" anf if actorFor (path) is present, otherwise create an actor. It's nice that you can enter the wizard at startup, and the code is much cleaner than the scout's, but he still has to decide what the weather will look for or create an actor. I think this cannot be avoided.

+1


source


I tried your git project and it does work fine except for a compile error and that you should start an sbt session with a parameter -Dakka.remote.netty.port=0

in the jvm, not as a parameter run

.



You should also understand that you do not need to run Counter Counter in both processes. In this example, it is intended to be created from the client and deployed to the server (port 2552). You don't need to run it on the server. This should be enough to create a live system on the server for this example.

0


source







All Articles