# How to implement remote messaging?
When two or more applications residing on different machines need to communicate with each other we use remote messaging.
For example to implement a simple master and slave on a remote server, we can start with the slave first registers to the master and the master responds with a welcome message before they start communicating task exchange messages. Here is how we set up remote-messaging for this scenario:
- Both the projects need to have a shared kprocess module which has the messages being exchanged defined. For example: SharedProcess.kprocess would have the following messages:
message Register(me:String,gap:Int)
message Welcome(you:String)
//other task related messages
...
- The master project will have a kprocess (say MasterProcess.kprocess) with a processor (BigBoss) defined to accept the
Registermessage and send aWelcometo the remote-slave.
processor BigBoss(bigBossHandler) singleton {
accept message-ref SharedProcess::Register
send remote (Worker) SharedProcess::Welcome
}
Note:
- String
bigBossHandleris the actorName used to reference the actor through actorPath - String
Workerhere is just any name given to the slave's processor.
- Slave project will also have its kprocess (say SlaveProcess.kprocess) with a processor (MyWorker) which has the definition of the remote message as follows:
processor MyWorker(myWorkerHandler) singleton {
accept message-ref SharedProcess::Welcome
send remote (BigBossHandler) SharedProcess::Register
}
Note: String BigBossHandler here is just a plain name given to the master's processor.
- Inorder to send a remote message to Master we use the SmileActor System's actorSelection api passing the configured actorPath of the master residing in the remote machine as follows:
class MyWorkerProcessorCode extends MyWorkerProcessor.Consumers {
override def initState: MyWorkerState = new MyWorkerState()
val masterHostPort = Smile.conf.getString("master.host.port").getOrElse("localhost:2552")
val bigBossHandlerURL = s"akka.tcp://SmileActorSystem@$masterHostPort/user/bigBossHandler"
def getBigBossActorSelection: akka.actor.ActorSelection = Smile.actorSystem.akkaActorSystem.actorSelection(bigBossHandlerURL);
override def preStart(): Unit = {
sendRemoteToBigBossHandler(to = getBigBossActorSelection, message = Register(me = "worker1", gap = 10), from = processor.actorRef)
}
override def process(message: Welcome, sender: ActorRef): Unit = {
println("Welcomed as " + message.you)
}
}
- Set up the akka remote actor configuration in master's Smile.conf with the actual hostname and port:
akka {
actor {
provider = "akka.remote.RemoteActorRefProvider"
warn-about-java-serializer-usage = false
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
netty.tcp {
hostname = "ec2-12-222-178-101.ap-southeast-1.compute.amazonaws.com"
port = 2552
}
}
}
- Set up the processor as a pinned-dispatcher: Smile.conf:
bigboss-handler-pinned-dispatcher {
executor = "thread-pool-executor"
type = PinnedDispatcher
}
Use this dispatcher as the props in dressUp in the ActorConfig.scala:
object BigBossActorConfig {
def dressUp(props: Props): Props = props.withDispatcher("bigboss-handler-pinned-dispatcher")
}
- In the master's BigBossHandlerCode, just need to reply back to the sender:
class BigBossProcessorCode extends BigBossProcessor.Consumers {
...
override def process(message: Register, sender: ActorRef): Unit = {
sendRemoteToWorker(to = sender, message = Welcome(message.me), from = processor.actorRef)
}
...
}