Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Message delivery sequence in akka actors

I'm pretty new to Akka and couldn't find the answer in the reference manual.

Suppose we have remote actors distributed in the cluster of 3 machines (A, B, C), where one actor lives on each machine and others have actorRef to 2 others, i.e.:

Machine A:
A (real actor)
-> B (ref)
-> C (ref)

Machine B:
-> A (ref)
B (real actor)
-> C (ref)

Machine C:
-> A (ref)
-> B (ref)
C (real actor)

Actor A executes following code:

bRef ! msg1
bRef ! msg2

Actor B executes following code in message handler:

case msg1 => 
    cRef ! msg3
    aRef ! msg4

Actor C executes following code in message handler:

case msg3 => 
    aRef ! msg5

Can I make the following assumptions (if any):

  1. actor B gets msg1 before it gets msg2

  2. actor A gets msg5 before it gets msg4

And the follow-up question which probably leads to understanding the above: Is message sent by the ! operator through the network truly asynchronously or does it wait until the receiving mailbox gets it? I.e. does the line

bRef ! msg1

block until actor B gets the message in its mailbox or does it spawn the thread which handles the delivery and continue executing

bRef ! msg2

before it even knows that actor B got msg1?

like image 476
Grozz Avatar asked Jun 01 '11 13:06

Grozz


People also ask

How can I send a message to an actor in Akka?

1) Akka Actor tell() Method It works on "fire-forget" approach. You can also use ! (bang) exclamation mark to send message. This is the preferred way of sending messages.

Which protocol does not provide guaranteed delivery ordering of messages and duplicate elimination?

The dead letter service follows the same rules with respect to delivery guarantees as all other message sends, hence it cannot be used to implement guaranteed delivery.

Why messages sent within the Akka framework should be immutable?

Messages should be immutable, since they are shared between different threads. It is a good practice to put an actor's associated messages as static classes in the AbstractBehavior's class. This makes it easier to understand what type of messages the actor expects and handles.

Are Akka actors single threaded?

Behind the scenes Akka will run sets of actors on sets of real threads, where typically many actors share one thread, and subsequent invocations of one actor may end up being processed on different threads.


1 Answers

For (1) you have the guarantee that msg1 will be enqueued by the dispatcher before msg2. What actually happens once they are enqueued is really dependent on which dispatcher you use: http://akka.io/docs/akka/1.1.2/scala/dispatchers.html, but in your case then so long as B can accept both messages then it will always receive msg1 before msg2.

For (2), no you do not have this guarantee. The ! method returns as soon as the dispatcher enqueues the message not when the message is accepted by the target actor's mailbox. The sending is then done in another thread and is subject to all kinds of race conditions.

Is message sent by the ! operator through the network truly asynchronously or does it wait until the receiving mailbox gets it?

You can use a BoundedMailbox with local actors to show that enqueuing messages to dispatchers is asynchronous with !:

class TestActor extends Actor {
  val mailboxCapacity = BoundedMailbox(capacity = 1)
  self.dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("test", 1, mailboxCapacity).build

  def receive = {
    case x: String => 
      Thread.sleep(1000)
      println("Received message")
    case _ => 
  }
}

val t = Actor.actorOf[TestActor]
t.start()

t ! "one"; t ! "two"; t ! "three"; println("Main thread");

Prints:

scala>     t ! "one"; t ! "two"; t ! "three"; println("Main thread");
Received message
Main thread

scala> Received message
Received message

Which means that code execution in the main thread continues before you even know whether or not the message will ever be delivered. In this case the message send could easily have timed out if we set a pushTimeout on the dispatcher and made Thread.sleep wait for longer than the timeout.

Compare this to using !!:

scala>     t !! "one"; t !! "two"; t !! "three"; println("test");
Received message
Received message
Received message
test

So, with this in mind. The way to achieve (2) would be:

case msg1 =>
  cRef !! msg3
  aRef ! msg4 
like image 155
David McLaughlin Avatar answered Oct 06 '22 23:10

David McLaughlin