Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the absolute remote actor url from inside the actor?

Tags:

scala

akka

I want to do do something like this .

Actor A :

    actorB ! "info"

     def receive()={
     case _ => {
          println("Remote address is "+ _)

        }
}

Actor B : (this deployed remotely )

def receive()={
 case "info" => {
      sender tell self.path.address.toString

    }

}

I want it to return me the string akka://10.4.20.40:2555/slave/user/slaverunner . But what I get is just akka://slave. How do I get the remote host and port? . The properties host,port and hostport on the address object dont return anything

like image 408
questionersam Avatar asked Jan 11 '13 23:01

questionersam


3 Answers

For recent akka versions (2.1+) use this:

class RemoteAddressExtensionImpl(system: ExtendedActorSystem) extends Extension {
  def address = system.provider.getDefaultAddress
}

object RemoteAddressExtension extends ExtensionKey[RemoteAddressExtensionImpl]

val remoteAddr = RemoteAddressExtension(context.system).address
val remotePath = self.path.toStringWithAddress(remoteAddr))

the remotePath is what you were looking for:

I want it to return me the string akka://10.4.20.40:2555/slave/user/slaverunner

For more recent akka versions (2.5.3) use this:

class RemoteAddressExtensionImpl(system: ExtendedActorSystem) extends Extension {
  def address = system.provider.getDefaultAddress
}

object RemoteAddressExtension extends ExtensionId[RemoteAddressExtensionImpl]
with ExtensionIdProvider {
  override def lookup = RemoteAddressExtension
  override def createExtension(system: ExtendedActorSystem) = new RemoteAddressExtensionImpl(system)
  override def get(system: ActorSystem): RemoteAddressExtensionImpl = super.get(system)
}
like image 183
Ram Janovski Avatar answered Nov 15 '22 23:11

Ram Janovski


If you call

sender.path.toString

in actor A you will get the address of the sender. So you don't need to pass the address to another actor system as long as you can send a message to it.

Akka will not give you a remote path for an actor in the local system, which is why self.path.address.toString in actor B won't work.

If you really want to send the host and port from B to A then you'll need to get access to a RemoteActorRefProvider via the ExtendedActorSystem. The official way to do that is through an Extension. For example:

class MyExtensionImpl(system: ExtendedActorSystem) extends Extension {
  def address = system.provider match {
    case rarp: RemoteActorRefProvider => rarp.transport.address
    case _ => system.provider.rootPath.address
  }
}

object MyExtension extends ExtensionKey[MyExtensionImpl]

val address = MyExtension(system).address

And that will give you the exact address that you need to communicate remotely with B.

(note this code works with Akka 2.0.x. In 2.1.x you can avoid going through RemoteActorRefProvider by using system.provider.getDefaultAddress)

In Akka if you are using constructing actor addresses this way for use with actorFor then you need to make sure the hostnames match exactly.

For example if the ActorSystem thinks the host is foo.bar.com, then it will ignore the messages sent by a remote host to actorFor("akka://slave@foo:2555/user/slaverunner")

like image 37
sourcedelica Avatar answered Nov 16 '22 00:11

sourcedelica


I got this wrapped String:

 ConfigString("akka://[email protected]:2552")

Using system.settings:

context.system.settings.config.getValue("akka.actor.deployment.\"/root\".remote")

Actor was a "root" actor, in a fabric scheme suggested by Viktor Klang in a mail group discussion concerning "determine if actor is dead". It was created like this:

lazy val rootActor = actorSystem.actorOf(Props[Root], "root")

from ActorSystem that was created like this:

lazy val actorSystem = ActorSystem("serversys", ConfigFactory.parseString(""" 
akka {
  loglevel = "DEBUG"
  actor {
    provider = "akka.remote.RemoteActorRefProvider"
  }
  remote {
    transport = "akka.remote.netty.NettyRemoteTransport"
  }
}
serverconf {
  include "common"
  akka {
    actor {
      deployment {
        /root {
          remote = "akka://[email protected]:2552"
        }    
      }
    }
    remote {
      netty {
        hostname = "127.0.0.1"
        port = 2552
      }
    }
  }
}
""").getConfig("serverconf"))

Tested in Scala 2.9.2 REPL with Akka 2.0.3 that I still use.

Unwrap actual value using Config docs here: http://typesafehub.github.com/config/v0.3.0/

like image 29
idonnie Avatar answered Nov 16 '22 00:11

idonnie