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):
actor B gets msg1 before it gets msg2
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?
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With