As mentioned in the tutorial Introduction to Apache Akka, Akka Actors communicate with each other using messages, which are any type of object but they must be immutable. In general, objects like String, Int, Boolean are all immutable objects.
In this tutorial, we will study three ways of sending Akka messages: Message Sending, Message Replying and Message Forwarding (Message Receiving was already explained on the tutorial Writing a basic Akka program):
* Message Sending: Akka messages can be sent by either of the following two methods:
– tell() or “!”: based on fire-forget principle (sending a message but do not wait for reply). If the message is sent from an actor, the sender will be that actor, otherwise it will be deadLetters by default.
– ask() or “?”: based on Send-And-Receive-Future (Future is the possible reply that can be received in the future. If we don’t get Future within a specified time, an AskTimeOutException error will occur. Unlike tell(), ask() doesn’t use sender(), so the sender is Actor.noSender (see more at here)
* Message Replying: we use sender() function to send a reply message to the sender. This function returns a result that is the ActorRef of the sender (reply message can be sent by either of two methods described in Message Sending)
* Message Forwarding: Akka allows user to forward message from one actor to another. In this case , the address/reference of the original sender is remained unchanged even if the message has been transmitted through several intermediate actors
Now, we will write a program that demonstrates the above three types of message sending by using ask() function to send a message from the main() function to MessageActor. After receiving the message, MessageActor send a reply message to the sender. It will also send a message to ChildActor using both forward() and tell() to compare the differences between these two methods. The full code of this program is provided below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import akka.actor.{Actor, ActorSystem, Props} import akka.pattern.ask import akka.util.Timeout import scala.concurrent.Await import scala.concurrent.duration._ //Define Actors by extending Actor trait class MessageActor extends Actor{ //Implement receive method def receive = { //Define how actor handle each message case msg:String => println(self.path.name+" received a message from "+sender().path.name+": "+msg) //Send a reply message to sender actor val senderActor=sender() senderActor ! self.path.name+" received message!!" //Create a child actor using context.actorOf() method val child = context.actorOf(Props[ChildActor], "ChildActor") //Sending message to ChildActor using forward() method println("nSending message to ChildActor using forward: ") child forward(msg) Thread.sleep(1000) //Sending message to ChildActor using tell() method println("nSending message to ChildActor using tell(): ") child ! msg // default case case _ =>println("Received unknown message!!!") } } //Define a ChildActor class ChildActor extends Actor { //Implement receive method def receive = { //Define how actor handle each message case msg:String => println(self.path.name+" received a message from "+sender().path.name+": "+msg) // default case case _ =>println("Received unknown message!!!") } } object MessageProcessor { def main(args: Array[String]): Unit = { //Creating an ActorSystem var actorSystem = ActorSystem("ActorSystem"); //Create a BasicActor called "TestActor" var actor = actorSystem.actorOf(Props[MessageActor],"MessageActor") //Sending a message using ask() method and wait for a reply implicit val timeout = Timeout(10 seconds); val future = actor ? "Hello from Actor.noSender"; val result = Await.result(future, timeout.duration); println("Reply message: "+result) //Terminate the actorSystem actorSystem.terminate() } } |
Run the program, we get the following result:
Because the ask() function uses Actor.noSender, the name of the sender that send message from the main() function is $a (if we continue sending other massages, the name of these messages’ sender will be $b, $c,…). In addition, if we use the forward() function to forward the message, the sender of this message is still $a. However if we uses the tell() function, the original sender is replaced by the Actor that uses tell() function (in this example it is MessageActor).