开发者

Message delivery sequence in akka actors

开发者 https://www.devze.com 2023-03-09 14:46 出处:网络
I\'m pretty new to Akka and couldn\'t find the answer in the reference manual. Suppose we have remote actors distribut开发者_Python百科ed in the cluster of 3 machines (A, B, C), where one actor lives

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

Suppose we have remote actors distribut开发者_Python百科ed 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?


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 


Erlang gives you the first guarantee, but not the second. Akka might give you the first guarantee as well, but it will certainly not give you the second guarantee.

I don't know the answer to your follow up question.

0

精彩评论

暂无评论...
验证码 换一张
取 消