Where to shutdown actors - scala

we have a lot of actors that get created as
class BankActor extends Actor{
def receive ={
case CreateCustomer(message) => context.actorOf(Props[CustomerActor]) ! message
}
}
And CustomerActor creates other actors in a similar manner. Reason for creating actors in such a way is potentially there will be hundreds(or even thousands) of CreateCustomer messages that BankActor will be receiving in them. I thought creating them on the fly is a better way (given Actor is a low memory footprint). I didn't think having a "pool" of CustomerActor was a right thing to do because biz req is clear there will be lots and lots of "CreateCustomer" messages. can you share your thoughts on this? Now going back to question about stopping "CustomerActor" : where should I be doing context.stop(self) inside "CustomerActor"'s "receive" method, should it be the last thing in every "case" block in there? What's the best practice around this?

Avoid creating top-level actors unless you have a good reason to. (Use context.actorOf)
Send the newly created actor a PoisonPill after the "message" if you don't want to encode the shutdown within the created actor.
class BankActor extends Actor{
def receive = {
case CreateCustomer(message) =>
val customer = context.actorOf(Props[CustomerActor])
customer ! message
customer ! PoisonPill // message ordering is preserved on a per-sender basis (for all normal mailboxes)
}
}

Related

Akka, dropping earlier messages

I would like to drop earlier messages from an actor. The base idea is to have a timestamp on each message, store it for the last processed message message and drop messages earlier than this timestamp.
I am thinking to create mailbox for that, however I don't know:
If it is a good idea to keep a state in a mailbox.
How I can share the state of the actor (that has the timestamp) with the mailbox.
Maybe I am trying to something wrong and there is a better alternative for that ?
Thanks
Writing a custom mailbox for that is overkill. You can solve it like this:
class MyActor extends Actor {
val timestampLimit: LocalDateTime = ???
def receive = {
case m: Message if (m.getTimeStamp.isBefore(timestampLimit)) => // drop
case m: Message => // process
}
}

Terminates all other actors once one actor finishes its work

I am pretty new to scala and akka. I wonder to ask terminates all other actors once one of the actor finishes its work.
The basic structure of the code is as below. There is a Master who takes in charge of 5 workers, which are generated by a RoundRobinPool. Every worker is doing some work and will send the result back to the Master. What I need to realize is to let the Master to terminate all other workers once one of them finishes its work and send it back to the Master. The master then will send some relative value to the main function and then the whole program terminates.
Any idea how to implement this?
//Code:
object X{
sealed trait Message
case class Result() extends Message
case class Work() extends Message
case class Result() extends Message
case class Totalresult() extends Message
class Worker extends Actor{
def receive={
case Work =>
sender ! Result}
}//End of class Worker
class Master(nrOfWorkers: Int) extends Actor{
val workerRouter =context.actorOf(RoundRobinPool(nrOfWorkers).props(Props[Worker])))
def receive={
case Calculate => calculateSender=sender
case Result => calculateSender ! Totoalresult()
}
}//End of class Master
def main(args: String) {
val system =ActorSystem("mysystem")
val master=system.actorOf(Props(new Master(5),name="master")
val future=master ? Calculate
}
}
One of the major supervisionary aspects of Akka is that a given actor is considered responsible for its children. In this case, that means that the death of the "Master" actor will automatically result in termination of all its children, so all you really need to do is have the "Master" actor terminate itself. This can be done in a number of ways, such as through a Kill or or PoisonPill message to itself - eg, adding the line: self ! PoisonPill straight after sending the TotalResult message back to calculateSender.
Note that in the particular scenario you have described in your code, you set up to receive a future of a result in your main, but don't include any processing (eg. an onComplete call, or using Await) of that result. You could, in such processing, include a call to system.shutdown() rather than having the "Master" terminate itself, which would then terminate all the actors as part of the shutdown process - just be sure to call that only after the future (and hence the actor effort behind it) has completed.
PS: see this question for more info about the differences between the different ways of terminating an actor.

How to initialise a scala/akka Actor in an event driven architecture?

I have got long running processes, let's say 2h to 1day. Each process starts its lifecycle with an update message and then continues to listen further concurrent updates. In the update message there is a unique target identifier.
If I want to represent each process with an Actor, how do I initialize the actor? I clearly need to do an atomic look-up/create operation based on the value of the identifier in the update message? How to do I design this with scala/akka?
Setup a single actor that performs the management of these process actors (say a ProcessManager actor). This actor will support requests to get a process actor for a particular process id. Internally, it will see if that child already exists or not. If it exists, it will respond to the sender with that ref. If not, it will create it and then respond to the sender with that ref. Because this manager actor processes it's mailbox serially (as all actors do), you don't have to worry about race conditions with the lookup/create. A very simplified example of this:
case class GetProcessHandler(processId:Int)
class ProcessManager extends Actor{
def receive = {
case GetProcessHandler(id) =>
val name = s"proc_$id"
val handler = context.child(name).getOrElse(
context.actorOf(Props[ProcessHandler], name)
)
sender ! handler
}
}
class ProcessHandler extends Actor{
def receive = {
...
}
}
You can specify your starting actors in your application.conf. And then your main program you can create/initialize these actors by using your ActorSystem.

Is it possible to use the Akka scheduler inside an actor?

I want to have the possibility to put actors to sleep for a while. The actors should decide themselves how long they are going to sleep. As Thread.sleep() is not a recommended way of doing this I thought of using the scheduler in akka. I therefore defined an actor were another actor can register for being woken up.
class Scheduler extends Actor {
def receive = {
case Sleep(duration) => context.system.scheduler.scheduleOnce(duration) {
sender ! Ring
}
}
}
But the sending actor never receives the Ring message.
So my questions are
Is scheduling with the scheduler recommended inside an actor?
Why is the sending actor never receiving the Ring message?
If this is not possible what is the recommended way of solving the problem?
Let me first answer the title question: yes, it is possible to use the scheduler inside an actor.
case Sleep(duration) =>
context.system.scheduler.scheduleOnce(duration, self, Ring)
Now to the question behind the question
You did not say what you actually want to achieve, so I’m making an educated guess here that you want the actor—which normally does something called “X”—to do something called “Y” for a while, suspending the “X” activity. The full solutions to this would be
class Sleepy extends Actor {
def receive = {
... // cases doing “X”
case Sleep(duration) =>
case object WakeUp
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
context.become({
case WakeUp => context.unbecome()
// drop the rest
}, discardOld = false)
}
}
The same could as well be implemented using the FSM trait and switching between the normal and the sleeping state. And of course you can do whatever you want while sleeping, e.g. mix in the Stash trait in Akka 2.1 and call stash() for all (or some) messages while sleeping, unstashAll() when getting the WakeUp message; or you could do something else altogether. Actors are very flexible.
What actors don’t do
Actors never really sleep, they always handle incoming messages. As shown above, you can define what that means, but the basic principle is that you cannot suspend an actor such that it will not process the messages in its mailbox.
You are closing over "sender" in your closure that's passed to the scheduler. This means that the Ring message is most likely being sent to the wrong actor. You should do this instead:
case Sleep(duration) =>
val s = sender
context.system.scheduler.scheduleOnce(duration) {
s ! Ring
}
}
Roland Kuhn's answer covers the subject, I just wanted to add that there's another common use-case for using the scheduler:
when sending a message to a different actor and waiting for this actor to respond, it's quite common to cap the wait with a timeout.
otherActor ! Request(...)
context.system.scheduler.scheduleOnce(duration, self, WakeUp)
...
case Response(...) => ...
case WakeUp => context stop self

Any way of appending to the act method in scala?

First off, I am new to Scala:
I am writing a logging facility in Scala that will simply be a class that extends the Actor class. This way a user can just extend this class and the logging features will be available. Basically, I want to write to a log file every time an actor that extends this class sends or receives a message. For clarification every actor will have its own log file which can be collated later. I am taking a Lamport clocks style approach to ordering the events by having each Actor (who extends this class) have their own time variable that gets updated on a message send-receive and the actor will compare the current time variable (simply a positive integer) with the sender's and update its time variable with the greater of the two.
For now I chose to make it a simple method like
sendMessage(recipient, message)
For sending messages. This will just log to the file that the actor is going to send a message to X.
Now, the part that I am stumped on is doing logging when receiving messages. When an actor gets a message I simply want to log this event in a format like
myLogFile.writeLine(self.ToString+": Got a message from "+X+" at time: "+messageSendTime+", processed the message at" +Math.max(myCurrTime+1, messageSendTime+1))
However I need to know who sent this message, unless I force upon the user to include this info (namely the sender's name, time variable, etc) in the messages themselves, it gets hard(er). Is there any way to get the reference of the actual sender? I want this to work with remote actors as well. The only way I can think of is if I append to the act method that the user defines in his/her class with some extra case statements like:
def act {
case => // the user's case statements
...
//somehow I append these statements to the end for the Logger class's use
case (LoggerClassRegisterInboundMessage, message, timeStamp)
InboundMessagesMap.put(timeStamp, message)
}
By having this functionality I can do all the logging "behind the scenes" with these hidden messages being sent whenever the user sends a message. However this only works if the sender also uses the Logging facility. So a more general question is: is there a way in Scala to get the name/toString of a sender in Scala regardless of the sender's class?
I'm actually OK with going with the assumption that every class that sends messages will extend the Logger class. So if anyone knows how to append to the act like or something similar to the above example I will be equally grateful!
As it was said in the comments, Akka is the way to go. It's so much more powerful than the current Scala Actor API which will become deprecated with 2.10 anyway.
But, to attack your specific problem, you could create a trait for actors which support logging, in a way similar to this (I don't know if this actually works, but you can try it):
trait LoggingActor extends Actor {
override def receive[R](pf: PartialFunction[Any, R]): R = {
//we are appending to the partial function pf a case to handle messages with logging:
val loggingPf = pf orElse {
case (LoggerClassRegisterInboundMessage, message, timeStamp) => {
//do somthing with this log message.
message //returning the unwrapped result afterwards
}
}
super.receive(loggingPf)
}
//overriding the send as well
override def !(msg: Any): Unit {
//Wrap it in a logging message
super ! (LoggerClassRegisterInboundMessage, msg, getTimestamp())
}
}
And you would create your actors with something like this:
val myActor = new MyActor with LoggingActor
Hope it helps !