Akka wait for computation of actor - akka

I would like to create a minimal example of an actor that sends off a message to an actor and then waits for the response of that actor. The reason for this example is that I want to use it in my thesis in context of disussing the usage other language features (e.g., futures) instead of pure actors. So the point here is that it has to be an actor that waits for a message before processing anything else.
The idea I had was to demonstrate an actor that requests a file to be read from disk, then does some long computation and then waits for the read to finish.
What I have so far is the following:
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import scala.io.Source
case class FileContents(content: String)
class WorkerActor extends Actor
{
def receive =
{
case "compute" =>
println("Computing!")
// Create actor to read the file
val reader = context.actorOf(Props[ReadFileActor])
reader ! ReadFile("/home/christophe/code/thesis-example/src/main/resources/file.txt")
// Heavy computation
Thread.sleep(5000)
case FileContents(content) =>
println("Got file content:\n" + content)
// Continue computation.
}
}
case class ReadFile(path: String)
class ReadFileActor extends Actor
{
def receive =
{
case ReadFile(path) =>
var contents: String = ""
for (line <- Source.fromFile(path).getLines())
{
contents += line
}
sender ! FileContents(contents)
}
}
object Main extends App
{
val system = ActorSystem("HelloSystem")
val worker = system.actorOf(Props[WorkerActor], name = "worker")
worker ! "compute"
worker ! "compute"
}
But what happens here is that WorkerActor receives the compute message, and then starts a child actor to read in the file. After the heave computation it receives the second compute message instead. And finally receives the two messages from the ReadFile actor.
What I actually want to happen is that WorkerActor receives the compute message, does the heavy computation and then waits until he receives the FileContents message. Only after that it can receive any other message (i.e., the second compute message).
I have read the docs and searched around for examples but i cant seem to find anything on it.
Disclaimer: I am not using Akka except for this small example in context of my thesis.

Just create several (pool of) workers for several compute messages instead of one worker, smthng like:
object Main extends App {
val system = ActorSystem("HelloSystem")
val router = system.actorOf(RoundRobinPool(2).props(Props[Worker]), "router")
router ! "compute"
router ! "compute"
}
If you want second worker to be launched after first:
def receive = {
case "compute" => ...
case FileContents(content) =>
println("Got file content:\n" + content)
// Continue computation.
context.parent ! "compute" //send to the pool
}
...
//Main:
router ! "compute"
Another option is to remember sender of "compute" (it will be your Main) and send the response back to the top-level:
var main = _
def receive = {
case "compute" =>
...
main = sender
case FileContents(content) =>
...
main ! "ack"
}
//Main:
(router ? "compute") foreach (_ => router ! compute)
If you don't like future here - you may rewrite it with actor:
//Main
class MainActor extends Actor {
def receive = {
case "start" => router ! "compute"
case "ack" => router ! "compute"
}
}
P.S. Blocking computations inside actor should be managed properly or they may lead to thread starvation.

Sounds like what you want is to keep processing this message until you get a response. in other words block
class WorkerActor extends Actor {
def receive = {
case "compute" =>
println("Computing!")
// Create actor to read the file
val reader = context.actorOf(Props[ReadFileActor])
val future: Future[FileContents] =
(reader ? ReadFile("file.txt").mapTo[FileContents]
// Heavy computation
Thread.sleep(5000)
// this will block current thread and thus the actor,
// so it will not process any other messages until
// future is completed or time is out
Await.result(future, timeout)
}
}
BUT, this is considered as a very bad thing in actor lands.

Related

How to restart an Akka actor by self?

When a child actor receives a custom RESTART message, the actor should restart itself.
(The purpose is to reset the actor member variables, reload external state from db, but not clear the actor internal message queue)
To implement the restart, one workaround is the child actor throws a custom exception, and the parent actor configures its OneForOneStrategy to restart the child actor for this specific exception type.
I'm wondering, if there's a more straightforward approach to do the restart?
The purpose is to reset the actor member variables, reload external state from db
I guess, this is probably the biggest issue, because loading external state might take time and also blocking operation, hence result of the operation is or should be Future[] - so while this future loading your actor should ignore all other messages, until state from DB will be received.
I think ActorCell#become method might help you in this case - so you can change receive method to another, which will ignore rest of messages, except message with DB state or data, and then switch back to regular receive.
Please, see code example below:
import akka.actor.Actor
import akka.pattern._
import scala.concurrent.Future
import scala.collection.mutable
// Database API and external state model example
case class DbExternalState()
trait Database {
def loadExternalState: Future[DbExternalState]
}
import RestartActor._
class RestartActor(database: Database) extends Actor {
private var state = ActorState()
private val suspendedMessages = mutable.Queue[Any]()
override def receive: Receive = defaultReceive
private def defaultReceive: Receive = {
case Restart => restartActorStart()
}
/**
* Wait until message with internal state received and ignore all the other messages (put back un queue)
*/
private def suspendedReceive: Receive = {
case ExternalStateLoaded(state) => restartActorFinish(state)
case message => suspendedMessages.enqueue(message)
}
private def restartActorStart(): Unit = {
import context.dispatcher
context.become(suspendedReceive)
database.loadExternalState.map(ExternalStateLoaded) pipeTo self
}
private def restartActorFinish(dbExternalState: DbExternalState): Unit = {
state = ActorState.initial(dbExternalState)
context.become(defaultReceive) // Return to normal message handling flow
suspendedMessages.foreach(message => self ! message)
suspendedMessages.clear()
}
}
object RestartActor {
// Restart
case object Restart
case class ExternalStateLoaded(state: DbExternalState)
case class ActorState(internalState: List[String] = Nil, externalState: DbExternalState = DbExternalState())
object ActorState {
def initial(externalState: DbExternalState): ActorState = ActorState(externalState = externalState)
}
}
Please, let me know suggestions were correct.
I hope this helps!

Sending message on Actor startup with real (non-temp) sender ActorRef?

I'd like an actor to send a message on startup and receive a reply later.
Sending the message from within preStart results in a temporary sender reference (because the Actor hasn't yet started?). So the reply will likely be a dead letter.
Any tips would be appreciated. Apologies if my premise is mis-informed - I am new to Akka.
One approach is to send a message to self in preStart:
class MyActor extends Actor {
def preStart(): Unit = {
self ! CallService
}
def receive = {
case CallService =>
(service ? ServiceRequest).mapTo[ServiceResponse].pipeTo(self)
case ServiceResponse =>
// do something with the response
}
}
As described in this answer, if you want the actor to send the message before it processes all other messages, then you could stash the other messages:
class MyActor extends Actor with Stash {
def preStart(): Unit = {
self ! CallService
}
def uninitialized: Receive = {
case CallService =>
(service ? ServiceRequest).mapTo[ServiceResponse].pipeTo(self)
unstashAll()
context.become(initialized)
case _ => stash() // if we get a message other than CallService, stash it
}
def initialized: Receive = {
case ServiceResponse =>
// do something with the response from the service
case ...
}
def receive = uninitialized
}
Your premise is indeed not correct: when preStart runs the actor is already fully started, it's self reference never is a temporary one. Without code it is impossible to help you further, though.
The sender should always be considered "temporary" -- cf. this blog post, for example:
The rule is simply never close over the sender method in a block of
code that is potentially executed in another thread, such as a
scheduled task or a Future. The trick is to capture the current sender
in a val, as illustrated below...
-- Closing Over An Akka Actor Sender In The Receive
Make a copy of sender, and then later when you are ready to reply, reply to that copy of the actorRef and not to "sender".

Stopping an Actor Instance and Waiting for it to Stop

I have the following piece of code in my Actor's (I call this Actor MasterActor) receive method:
override def receive: Receive = {
case StopActor(id, actorConfig) =>
log.info(s"Stopping actor with id = $id and config $actorConfig")
stopActor(id, powerPlantCfg).pipeTo(self)
context.become(waitForStop(sender()))
// Other messages... not shown here for simplicity
}
So what I'm doing above is to stop the actor and pipe the result of that which is a Future[Continue] (where Continue is a Monix Ack type) to the Actor that contains the above Receive method. The stopActor looks like this:
private def stopActor(id: Long, cfg: ActorConfig): Future[Ack] = async {
await(fetchActor(id).materialize) match {
case scala.util.Success(actorRef) =>
log.info(s"Stopping Actor with id = $id")
context.watch(actorRef)
context.stop(actorRef)
Continue
case scala.util.Failure(fail) =>
log.error(s"Could not fetch Actor instance for id = $id because of: $fail")
Continue
}
}
I'm doing the context.watch(actorRef) and this is how my waitForStop looks like:
private def waitForStop(source: ActorRef): Receive = {
case Continue =>
source ! Continue
context.become(receive)
case someShit =>
log.error(s"Unexpected message $someShit received while waiting for an actor to be stopped")
}
So I have 2 questions here:
When doing context.become(waitForStop(sender())), I'm closing in on the sender(), so I assume the sender in this case is the ActorRef that contains all this above code which is the MasterActor. Am I correct?
How do I know explicitly that this ActorRef that I'm trying to stop is actually stopped so that I can do a context.unwatch(actorRef) as soon as it is stopped?
Any suggestions?
You can be notified of the stop of an Actor by watching it. You are already familiar with watch:
val kenny = context.actorOf(Props[Kenny], name = "Kenny")
context.watch(kenny)
and then you can wait for a Terminated message. Once you receive it, you can unwatch what you need.
def receive = {
case Terminated(kenny) => println("OMG, they killed Kenny")
case _ => println("Parent received a message")
}
So my reccomendation would be to simply watch, become waiting for terminated, and issue the stop command. But I'm unsure what you are asking exactly, so this cvould be the wrong ans
Blog post example

how to avoid sending messages to actors not created yet?

I hope it is ok to ask this. I am using akka and have two actors, where one is initiated/created fast and the other much slower. The rapidly created one asks the other for something (ask-pattern), and the message is sent to dead letters since the other is not initiated yet. What is the preferred way of making an actor waiting with sending it´s message? I am not so eager to make an actor sleep or something without knowing there is no other way.
I would use the functionality become()/unbecome() Akka provides for Actors. I am assuming in the following code that the slowActor gets created by the fastActor. The trick here is that the fastActor will have two behaviors: one for when the slowActor is getting initiated and the other for when it's ready to do some work. When slowActor is ready, it will send a message to the fastActor to advertise that is able to receive messages. fastActor will be watching slowActor and if it gets terminated, it will change its behavior again. What to do next would be up to your solution.
Here is a mock code as a guide (I have not compiled the code and it might contain some errors):
case object Ready
case object DoWork
case object WorkDone
class FastActor extends Actor with ActorLogging {
val slowActor = context.actorOf(SlowActor.props)
context.watch(slowActor)
def receive = slowActorNotReadyBehavior
def slowActorNotReadyBehavior = {
case DoWork => log.warning("Slow actor in not ready, I am sorry...")
case Ready => context.become(slowActorReadyBehavior)
}
def slowActorReadyBehavior = {
case DoWork => (slowActor ? DoWork).pipeTo(self)
case Terminated(ref) =>
log.error("Slow actor terminated")
context.unbecome()
//... do something with slowActor
}
}
class SlowActor extends Actor {
override def preStart = {
context.parent ! Ready
}
def receive = {
case DoWork =>
//do something
sender ! WorkDone
}
}

Unit testing scala actors

Anyone know of a good way to unit test Scala actors? In the general sense I have an actor that receives a message and will send out other messages in response. This is done on multiple threads, and an actor that is not correct may either send the wrong messages or no message at all. I need a simple way of creating a mockup actor that send and receives messages to the actor being tested. Any experiences in this area?
Because of the dynamic nature of actor-style message passing, mocking actors is usually no trouble at all. Just create an actor which receives the desired message and you're home free. You will of course need to ensure that this mock actor is the one to which messages are passed, but that shouldn't be a problem as long as the actor you are attempting to test is reentrant.
I think the complexity depends on a couple factors...
How stateful is the actor?
If it behaves like a idempotent function, only asynchronous, then it should be a simple matter of mocking up an actor that sends a message and then checks that it receives the expected messages back. You probably want to use a react/receiveWithin on the mock actor in case there is response within a reasonable period of time you can fail rather than hanging.
However if the messages aren't independent of one another, then you should test it with various sequences of messages and expected results.
How many actors will the actor being tested interact with?
If an actor is expected to interact with many others, and it is stateful, then it should be tested with several actors sending/receiving messages. Since you probably have no guarantee of the order in which the messages will arrive, you should be sure to either permute the orders in which the actors send the messages or introduce random pauses in the actors generating messages and run the test many times.
I'm not aware of any prebuilt frameworks for testing actors, but you could possibly look to Erlang for inspiration.
http://svn.process-one.net/contribs/trunk/eunit/doc/overview-summary.html
I have been wondering about how to test Actors myself.
Here is what I came up with, does anybody see problems with this approach?
Rather than send messages directly, what if your actor delegated message sending to a function?
Then your tests can swap out the function with one that tracks the number of times called and/or the arguments with which the method was called:
class MyActor extends Actor {
var sendMessage:(Actor, ContactMsg) => Unit = {
(contactActor, msg) => {
Log.trace("real sendMessage called")
contactActor ! msg
}
}
var reactImpl:PartialFunction(Any, Unit) = {
case INCOMING(otherActor1, otherActor2, args) => {
/* logic to test */
if(args){
sendMessage(otherActor1, OUTGOING_1("foo"))
} else {
sendMessage(otherActor2, OUTGOING_2("bar"))
}
}
}
final def act = loop {
react {
reactImpl
}
}
Your test case might contain code like:
// setup the test
var myActor = new MyActor
var target1 = new MyActor
var target2 = new MyActor
var sendMessageCalls:List[(Actor, String)] = Nil
/*
* Create a fake implementation of sendMessage
* that tracks the arguments it was called with
* in the sendMessageCalls list:
*/
myActor.sendMessage = (actor, message) => {
Log.trace("fake sendMessage called")
message match {
case OUTGOING_1(payload) => {
sendMessageCalls = (actor, payload) :: sendMessageCalls
}
case _ => { fail("Unexpected Message sent:"+message) }
}
}
// run the test
myActor.start
myActor.reactImpl(Incoming(target1, target2, true))
// assert the results
assertEquals(1, sendMessageCalls.size)
val(sentActor, sentPayload) = sendMessageCalls(0)
assertSame(target1, sentActor)
assertEquals("foo", sentPayload)
// .. etc.
My attempt at unit testing an actor (it works). I'm using Specs as a framework.
object ControllerSpec extends Specification {
"ChatController" should{
"add a listener and respond SendFriends" in{
var res = false
val a = actor{}
val mos = {ChatController !? AddListener(a)}
mos match{
case SendFriends => res = true
case _ => res = false
}
res must beTrue
}
How this works is by sending a synchronous call to the singleton ChatController. ChatController responds by use of reply(). The response is sent as a return of the called function, which gets stored into mos. Then a match is applied to mos getting the case class that was sent from ChatController. If the result is what is expected (SendFriends) set res to true. The res must beTrue assertion determines the success or failure of test.
My actor singleton that I'm testing
import ldc.socialirc.model._
import scala.collection.mutable.{HashMap, HashSet}
import scala.actors.Actor
import scala.actors.Actor._
import net.liftweb.util.Helpers._
//Message types
case class AddListener(listener: Actor)
case class RemoveListener(listener: Actor)
case class SendFriends
//Data Types
case class Authority(usr: Actor, role: String)
case class Channel(channelName: String, password: String, creator: String, motd: String, users: HashSet[Authority])
object ChatController extends Actor {
// The Channel List - Shows what actors are in each Chan
val chanList = new HashMap[String, Channel]
// The Actor List - Shows what channels its in
val actorList = new HashMap[Actor, HashSet[String]]
def notifyListeners = {
}
def act = {
loop {
react {
case AddListener(listener: Actor)=>
actorList += listener -> new HashSet[String]
reply(SendFriends)
}
}
}
start //Dont forget to start
}
Though its not complete it does return the Sendfriends case class as expected.
Suite for unit testing of Actors has recently been added to Akka. You can find some information and code snippets in this blogpost.