I understand in actor based system,like Akka, Actors work in isolation and don't interact directly. Instead they send messages to each other. An actor just sends a message and go to other task. This helps in avoiding blocking.
But if actor can't progress without the response, then how does it help in achieving asynchronous behaviour? Won't actor need to wait for the response?
Usually an actor should not wait for a response to continue its execution. An actor receives and send messages, that is their purpose, but what is the progress of one actor?. An actor can implement a protocol or to be part of it but it´s not a good idea to block the inner thread execution waiting for some event to come.
class SomeActor(receiver: ActorRef) extends Actor {
case SomeMessage(msg) =>
receiver ! s"Hey ${msg}"
case SomeResponse(resp) =>
println(s"Received response ${resp}"
}
In this example the actor handles asynchronously SomeMessage events, and soon as they arrive it sends them to another but it never stops. At any moment the response to the "Hey .. " message will come and the actor will act printing the message.
Another possible implementation:
class SomeActor(receiver: ActorRef) extends Actor {
case SomeMessage(msg) =>
receiver ? s"Hey ${msg}" onComplete { case Success(resp) =>
println(s"Received response ${resp}"
}
}
I don´t use this but it does not block neither. It creates futures for each incoming message and handle the response inside the future´s callback.
The following is more related to your question:
class SomeActor(receiver: ActorRef) extends Actor {
case SomeMessage(msg) =>
val resp = Await.result(receiver ? s"Hey ${msg}")
println(s"Received response ${resp}"
}
}
That blocks the future´s execution, but in this way you are using the actor as a synchronous unit of execution so it does not make any sense using actors in these scenarios, at least I wouldn't do it.