Akka actor ask pattern does not work as expected - scala

Actor B contains reference to actor A called senderr. Actor A asks actor B, waits the response and prints it. However it does not receive response. Why? It must print number 4 at the console but it doesn't.
class A(b: ActorRef) extends Actor {
private implicit val timeout = Timeout(20 seconds)
b ! 1
def receive = {
case 2 => (b ? 3).map(println)
}
}
class B extends Actor {
var senderr : ActorRef = null
def receive = {
case 1 =>
senderr = sender()
sender ! 2
case 3 =>
senderr ! 4
}
}
object Main extends App {
val system = ActorSystem("test")
val b = system.actorOf(Props[B])
val a = system.actorOf(Props(classOf[A], b))
}

ask basically creates a temporary micro-actor with the single purpose of receiving one response of type Any
When B receives 3 it sends 4 to senderr which refers to A. However A does not have a match for 4. In order for (b ? 3).map(println) to receive the 4, B has to send it to sender(), which at that time refers to the temporary actor set up by ask:
case 3 => sender ! 4
Alternatively, you could have a case 4 in A but then you wouldn't even need to use ask

Related

Akka actor - messaging neighbours

Consider that i have four actors(1,2,3,4) in a same actor system.Each actor can send message only with its neighbors who has not sent a message to it(i.e. 1 can send only to 2 and 4. Also 2 and 4 can only send to 3 because their neighbor 1 has already sent a message). when an actor receives message from both its neighbors, it prints its name and the system stops.I am able to partially implement.But issue here is in the same time two actors gets message from both their neighbors and stops.For example, if i start the process at 1, 1 sends message to 4 and 2,2 to 3 and 4 to 3 so theoretically 3 should get printed but i get 2 and 3 both printed.Please suggest what can be done.Below is my sample logic.
object Main extends App {
//creating a actor system
val actorSystem = ActorSystem("System")
//creating four actor instances with id as 1,2,3,4
for (i <- 1 to 4) {
actorSystem.actorOf(CircularActor.props(4), "" + i)
}
//initiating message to actor 1
actorSystem.actorSelection(s"/user/1") ! "hello from x"
}
class CircularActor(n: Int) extends Actor {
//variable to keep a track whether the actor received two meesages(i.e.from both neighbours)
var noOfMessagesReceived = 0
//generic method to send message using actorPath
def messageNeighbour(path:String){
context.actorSelection(path) ! "hello from x"
}
override def receive: Receive = {
case "hello from x" =>
noOfMessagesReceived += 1
if (noOfMessagesReceived == 2) {
println(s"The actor that received both messages is ${self.path.name}")
context.system.terminate()
}
else {
//Figures out id of sender
val pathValue = sender().path.name
//Gets its own name
val ownId = self.path.name.toInt
//Finds out the previous neighbor
val prev = if (ownId - 1 == 0) n else ownId - 1
//Finds next neighbour
val next = if (ownId == n) 1 else ownId + 1
//If the message is from deadletter, then this is the initiator actor
if (pathValue == "deadLetters") {
messageNeighbour(s"/user/$prev")
messageNeighbour(s"/user/$next")
}
//If the message is from its next neighbour,send it to previous
else if (pathValue.toInt == next) {
//introducing random delay
Thread.sleep(1 + Random.nextInt(100))
messageNeighbour(s"/user/$prev")
}
//If none of above,then send it to previous.
else {
Thread.sleep(1 + Random.nextInt(100))
messageNeighbour(s"/user/$next")
}
}
}
object CircularActor {
def props(n: Int): Props = Props(new CircularActor(n))
}
The problem seems to be that you assume that messages are processed in the order in which they are sent, which is not necessarily the case. Message passing is asynchronous, and the only guarantee is that messages are processed in the order that they arrive for any given actor. The order in which messages are processed by different actors is not defined.
So in your system the messages could be processed in this order
<dead> -> 1
1 -> 2,4
4 -> 3
3 -> 2
2 -> 3
2 -> <terminate>
As you can see, actor 2 processes two messages before any other actor.
It is not clear what can be done because it is not clear what you are trying to achieve. But it is dangerous to build actor systems with loops like this. In general, an actor system should be organised as a tree or DAG of requests, with replies sent to the requesting actor.
To achieve required behavior we need an actor for tracking the actors to which messages are received.
Model:
abstract class Direction
object Left extends Direction
object Right extends Direction
object StartPoint extends Direction
object Process
BookKeeper Actor
class BookKeeperActor extends Actor {
var visitedActorRefs: mutable.HashSet[String] = mutable.HashSet.empty[String]
override def receive: Receive = {
case Process =>
if (visitedActorRefs.contains(sender().path.toString)) {
context.stop(self)
context.system.terminate()
println(s"The actor that received both messages is ${sender().path.toString}")
}
else
visitedActorRefs.add(sender().path.toString)
}
}
Circular Actor:
class CircularActor(n: Int, bookKeeper: ActorRef) extends Actor {
//generic method to send message using actorPath
def messageNeighbour(path: String, direction: Direction) {
context.actorSelection(path) ! ("hello from x", direction)
}
override def receive: Receive = {
case ("hello from x", direction: Direction) =>
bookKeeper ! Process
//Figures out id of sender
val pathValue = sender().path.name
//Gets its own name
val ownId = self.path.name.toInt
//Finds out the previous neighbor
val prev = if (ownId - 1 == 0) n else ownId - 1
//Finds next neighbour
val next = if (ownId == n) 1 else ownId + 1
Thread.sleep(1 + Random.nextInt(100))
direction match {
case StartPoint =>
messageNeighbour(s"/user/$prev", Left)
messageNeighbour(s"/user/$next", Right)
case Left => messageNeighbour(s"/user/$prev", Left)
case Right => messageNeighbour(s"/user/$next", Right)
}
}
}
object CircularActor {
def props(n: Int, bookeeper: ActorRef): Props = Props(new CircularActor(n, bookeeper))
}
Main App-
object Main extends App {
val actorSystem = ActorSystem("System")
//creating four actor instances with id as 1,2,3,4
val bookKeeperActor = actorSystem.actorOf(Props(new BookKeeperActor))
for (i <- 1 to 4) {
val ac = actorSystem.actorOf(CircularActor.props(4, bookKeeperActor), "" + i)
}
//initiating message to actor 1
actorSystem.actorSelection(s"/user/1") ! ("hello from x", StartPoint)
}

Akka Router increment counter on message arrival from routees

I'm trying to keep counting on each successful import. But here is a problem - Counter works if the router receives a message from its parent but if I'm trying to send a message from its children it receives it but doesn't update the global variable that is out of the scope.
I know it sounds complicated. Let me show you the code.
Here is the router
class Watcher(size: Int) extends Actor {
var router = {
val routees = Vector.fill(size) {
val w = context.actorOf(
Props[Worker]
)
context.watch(w)
ActorRefRoutee(w)
}
Router(RoundRobinRoutingLogic(), routees)
}
var sent = 0
override def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 100) {
case _: DocumentNotFoundException => {
Resume
}
case _: Exception => Escalate
}
override def receive: Receive = {
case container: MessageContainer =>
router.route(container, sender)
case Success =>
sent += 1
case GetValue =>
sender ! sent
case Terminated(a) =>
router.removeRoutee(a)
val w = context.actorOf(Props[Worker])
context.watch(w)
router = router.addRoutee(w)
case undef =>
println(s"${this.getClass} received undefinable message: $undef")
}
}
Here is the worker
class Worker() extends Actor with ActorLogging {
var messages = Seq[MessageContainer]()
var received = 0
override def receive: Receive = {
case container: MessageContainer =>
try {
importMessage(container.message, container.repo)
context.parent ! Success
} catch {
case e: Exception =>
throw e
}
case e: Error =>
log.info(s"Error occurred $e")
sender ! e
case undef => println(s"${this.getClass} received undefinable message: $undef")
}
}
So on supervisor ? GetValue I get 0 but suppose to have 1000.The strangest thing is that when I debug it with the breakpoint right on the case Success => ... the value is incremented every time the new message arrives. But supervisor ? GetValue still returns 0.
Let's assume I want to count on case container: MessageContainer => ... and it will magically work; I'll get desirable number, but it doesn't show if I actually imported anything. What's going on?
Here is the test case.
#Test
def testRouter(): Unit = {
val system = ActorSystem("RouterTestSystem")
// val serv = AddressFromURIString("akka.tcp://master#host:1334")
val supervisor = system.actorOf(Props(new Watcher(20)))//.withDeploy(akka.actor.Deploy(scope = RemoteScope(serv))))
val repo = coreSession.getRepositoryName
val containers = (0 until num)
.map(_ => MessageContainer(MessageFactory.generate("/"), repo))
val watch = Stopwatch.createStarted()
(0 until num).par
.foreach( i => {
supervisor ! containers.apply(i)
})
implicit val timeout = Timeout(60 seconds)
val future = supervisor ? GetValue
val result = Await.result(future, timeout.duration).asInstanceOf[Int]
val speed = result / (watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0)
println(f"Import speed: $speed%.2f")
assertEquals(num, result)
}
Can you please explained it in details. Why is it happening? Why only on message received from the children? Another approach?
Well... there can be many potential problems hidden in the parts of code that you have not shared. But, for the sake of this discussion I will assume that everything else is fine and we will just discuss problems with your shared code.
Now, let me explain a bit about Actors. To put things simply, every actor has a mailbox (where it keeps messages in the sequence they were received) and processes them one by one in the order they were received. Since the mailbox is used like a Queue we will refer to it as a Queue in this discussion.
Also... I don't know what this container.apply(i) is going to return... so I will refer to the return value of that container.apply(1) as MessageContainer__1
In your test runner you are first creating an instance of Watcher,
val supervisor = system.actorOf(Props(new Watcher(20)))
Now, lets say that you are sending these 2 messages (num = 2) to supervisor,
So supervisor's mailbox will look something like,
Queue(MessageContainer__0, MessageContainer__1)
Then you send it another message GetValue so the mailbox will look like,
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Now the actor will process the first message and pass it to the workers, the mail-box will look like,
Queue(MessageContainer__1, GetValue)
Now even if your worker is ultra-fast and instantaneous in sending the reply the mailbox will look like,
Queue(MessageContainer__1, GetValue, Success)
And now since your worker super-ultra-fast and instantaneously replies with a Success, the state after passing the second MessageContainer will look like,
Queue(GetValue, Success, Success)
And... here is the root of your problem. The Supervisor sees the GetValue massage before any Success messages, no matter how fast your workers are.
And thus it will process GetValue and reply with current value of sent which is 0.

Akka: The order of responses

My demo app is simple. Here is an actor:
class CounterActor extends Actor {
#volatile private[this] var counter = 0
def receive: PartialFunction[Any, Unit] = {
case Count(id) ⇒ sender ! self ? Increment(id)
case Increment(id) ⇒ sender ! {
counter += 1
println(s"req_id=$id, counter=$counter")
counter
}
}
}
The main app:
sealed trait ActorMessage
case class Count(id: Int = 0) extends ActorMessage
case class Increment(id: Int) extends ActorMessage
object CountingApp extends App {
// Get incremented counter
val future0 = counter ? Count(1)
val future1 = counter ? Count(2)
val future2 = counter ? Count(3)
val future3 = counter ? Count(4)
val future4 = counter ? Count(5)
// Handle response
handleResponse(future0)
handleResponse(future1)
handleResponse(future2)
handleResponse(future3)
handleResponse(future4)
// Bye!
exit()
}
My handler:
def handleResponse(future: Future[Any]): Unit = {
future.onComplete {
case Success(f) => f.asInstanceOf[Future[Any]].onComplete {
case x => x match {
case Success(n) => println(s" -> $n")
case Failure(t) => println(s" -> ${t.getMessage}")
}
}
case Failure(t) => println(t.getMessage)
}
}
If I run the app I'll see the next output:
req_id=1, counter=1
req_id=2, counter=2
req_id=3, counter=3
req_id=4, counter=4
req_id=5, counter=5
-> 4
-> 1
-> 5
-> 3
-> 2
The order of handled responses is random. Is it normal behaviour? If no, how can I make it ordered?
PS
Do I need volatile var in the actor?
PS2
Also, I'm looking for some more convenient logic for handleResponse, because matching here is very ambiguous...
normal behavior?
Yes, this is absolutely normal behavior.
Your Actor is receiving the Count increments in the order you sent them but the Futures are being completed via submission to an underlying thread pool. It is that indeterminate ordering of Future-thread binding that is resulting in the out of order println executions.
how can I make it ordered?
If you want ordered execution of Futures then that is synonymous with synchronous programming, i.e. no concurrency at all.
do I need volatile?
The state of an Actor is only accessible within an Actor itself. That is why users of the Actor never get an actual Actor object, they only get an ActorRef, e.g. val actorRef = actorSystem actorOf Props[Actor] . This is partially to ensure that users of Actors never have the ability to change an Actor's state except through messaging. From the docs:
The good news is that Akka actors conceptually each have their own
light-weight thread, which is completely shielded from the rest of the
system. This means that instead of having to synchronize access using
locks you can just write your actor code without worrying about
concurrency at all.
Therefore, you don't need volatile.
more convenient logic
For more convenient logic I would recommend Agents, which are a kind of typed Actor with a simpler message framework. From the docs:
import scala.concurrent.ExecutionContext.Implicits.global
import akka.agent.Agent
val agent = Agent(5)
val result = agent()
val result = agent.get
agent send 7
agent send (_ + 1)
Reads are synchronous but instantaneous. Writes are asynch. This means any time you do a read you don't have to worry about Futures because the internal value returns immediately. But definitely read the docs because there are more complicated tricks you can play with the queueing logic.
Real trouble in your approach is not asynchronous nature but overcomplicated logic.
And despite pretty answer from Ramon which I +1d, yes there is way to ensure order in some parts of akka. As we can read from the doc there is message ordering per sender–receiver pair guarantee.
It means that for each one-way channel of two actors there is guarantee, that messages will be delivered in order they been sent.
But there is no such guarantee for Future task accomplishment order which you are using to handle answers. And sending Future from ask as message to original sender is way strange.
Thing you can do:
redefine your Increment as
case class Increment(id: Int, requester: ActorRef) extends ActorMessage
so handler could know original requester
modify CounterActor's receive as
def receive: Receive = {
case Count(id) ⇒ self ! Increment(id, sender)
case Increment(id, snd) ⇒ snd ! {
counter += 1
println(s"req_id=$id, counter=$counter")
counter
}
}
simplify your handleResponse to
def handleResponse(future: Future[Any]): Unit = {
future.onComplete {
case Success(n: Int) => println(s" -> $n")
case Failure(t) => println(t.getMessage)
}
}
Now you can probably see that messages are received back in the same order.
I said probably because handling still occures in Future.onComplete so we need another actor to ensure the order.
Lets define additional message
case object StartCounting
And actor itself:
class SenderActor extends Actor {
val counter = system.actorOf(Props[CounterActor])
def receive: Actor.Receive = {
case n: Int => println(s" -> $n")
case StartCounting =>
counter ! Count(1)
counter ! Count(2)
counter ! Count(3)
counter ! Count(4)
counter ! Count(5)
}
}
In your main you can now just write
val sender = system.actorOf(Props[SenderActor])
sender ! StartCounting
And throw away that handleResponse method.
Now you definitely should see your message handling in the right order.
We've implemented whole logic without single ask, and that's good.
So magic rule is: leave handling responses to actors, get only final results from them via ask.
Note there is also forward method but this creates proxy actor so message ordering will be broken again.

How to send iterables between actors or from an actor to a Future?

A future from the main method of a program sends a msg to its actor asking for an iterable object. The actor then creates another future that asks for the iterable object (say an ArrayBuffer) from a remote actor. After receiving the ArrayBuffer from the remote actor, how would the actor send it back to the first future in the main method? It seems creating a local alias of sender and creating a separate case class to represent the iterable does not prevent dead letters from being encountered.
Here is a sample code:
case class SequenceObject(sqnce:Seq[someArrayBuffer])
//...
implicit val timeout = Timeout(10 seconds)
val fut1: Future[Any] = myActor ? iNeedAnArrayBufferObject
fut1.onSuccess {
case listOfItems: SequenceObject => {
//do sth with listofItems.sqnce
}
class myActor extends Actor {
implicit val timeout = Timeout(1 seconds)
def receive = {
case a: iNeedAnArrayBufferObject => {
val originalSender = sender
val fut: Future[Any] = (remoteActor ? a)
fut.onSuccess {
case list: SequenceObject => {
originalSender ! SequenceObject(list.sqnce)
}
}
The remote actor code is:
class ServerActorClass extends Actor {
def receive = {
case a: iNeedAnArrayBufferObject => {
val closer = sender()
closer ! SequenceObject(ArrayBufferObject[information])
}
}
The above does not seem to work. The remote actor and the local actor can communicate and messages are received correctly. However, the iterable object is never send back to fut1. Why is that? Thanks in advance.
Check pipeTo pattern in Ask: Send-And-Receive-Future section

Ask an actor and let him respond when he reaches a particular state in Akka 2

I'm quite new to Akka so my question may seem simple:
I have an actor called workerA that uses FSM and can thus be either in those two states Finishedand Computing:
sealed trait State
case object Finished extends State
case object Computing extends State
sealed trait Data
case object Uninitialized extends Data
case class Todo(target: ActorRef, queue: immutable.Seq[Any]) extends Data
When workerA receives GetResponse it should answer if and if only it is in state Finished.
What is the proper way of doing this? I know we should avoid to be blocking in this paradigm but here it is only the top actor which is concerned.
Thanks
I'm not necessarily sure you even need FSM here. FSM is a really good tool for when you have many states and many possible (and possibly complicated) state transitions between those states. In your case, if I understand correctly, you basically have two states; gathering data and finished. It also seems that there is only a single state transition, going from gathering -> finished. If I have this all correct, then I'm going to suggest that you simply use become to solve your problem.
I have some code below to show a trivial example of what I'm describing. The basic idea is that the main actor farms some work off to some workers and then waits for the results. If anyone asks for the results while the work is being done, the actor stashes that request until the work is done. When done, the actor will reply back to anyone that has asked for the results. The code is as follows:
case object GetResults
case class Results(ints:List[Int])
case object DoWork
class MainActor extends Actor with Stash{
import context._
override def preStart = {
val a = actorOf(Props[WorkerA], "worker-a")
val b = actorOf(Props[WorkerB], "worker-b")
a ! DoWork
b ! DoWork
}
def receive = gathering(Nil, 2)
def gathering(ints:List[Int], count:Int):Receive = {
case GetResults => stash()
case Results(i) =>
val results = i ::: ints
val newCount = count - 1
if (newCount == 0){
unstashAll()
become(finished(results))
child("worker-a") foreach (stop(_))
child("worker-b") foreach (stop(_))
}
else
become(gathering(results, newCount))
}
def finished(results:List[Int]):Receive = {
case GetResults => sender ! results
}
}
class WorkerA extends Actor{
def receive = {
case DoWork =>
//Only sleeping to simulate work. Not a good idea in real code
Thread sleep 3000
val ints = for(i <- 2 until 100 by 2) yield i
sender ! Results(ints.toList)
}
}
class WorkerB extends Actor{
def receive = {
case DoWork =>
//Only sleeping to simulate work. Not a good idea in real code
Thread sleep 2000
val ints = for(i <- 1 until 100 by 2) yield i
sender ! Results(ints.toList)
}
}
Then you could test it as follows:
val mainActor = system.actorOf(Props[MainActor])
val fut = mainActor ? GetResults
fut onComplete (println(_))
You can pattern match on FSM states:
// insert pattern matching stuff instead of ...
class MyActor extends Actor with FSM[State, Message] {
startWith(Finished, WaitMessage(null))
when(Finished) {
case Event(Todo(... =>
// work
goto(Computing) using Todo(...)
case Event(GetResponse(... =>
// reply: sender ! msg // or similar
}
/* the rest is optional. You can use onTransition below to send yourself a message to report status of the job: */
when(Busy) {
case Event(Finished(... =>
// reply to someone: sender ! msg // or similar
goto(Finished)
}
onTransition {
case Finished -> Computing =>
// I prefer to run stuff here in a future, and then send a message to myself to signal the end of the job:
self ! Finished(data)
}
An Edit to more specifically address the question:
class MyActor extends Actor with FSM[State, Message] {
startWith(Finished, WaitMessage(null))
when(Finished) {
case Event(Todo(... =>
// work
goto(Computing) using Todo(...)
case Event(GetResponse(... =>
// reply: sender ! msg // or similar
stay
}
initialize()
}