Akka - How to handle termination - scala

I am using the redis-react-nb library with my akka application. Unfortunately, when a connection to redis lost the library will stop itself with context stop self
This means that my application receives a termination notification like so:
def receive: Actor.Receive = {
case Terminated(actorRef) =>
...
}
So I'm wondering what to do here. Ideally I want to restart all children actors so they will all be initialised with a new redis connection - basically resetting the actor system to its initial state.
Am I missing something conceptually? Or is there a way for an actor to restart all of it's children without receiving an exception? self ! RestartAll or something similar?

Another way to look at this is to say that the actor you are talking about depends on the redis actor, it cannot continue its work without it. In that case it would be appropriate to escalate that as a failure to its parent and let that do the restart. If you do not handle the Terminated message, then a DeathPactException will be thrown, but you will have to install an appropriate supervisorStrategy in the parent since the default for that one is to terminate the child. I would recommend defining and throwing a RedisFailedException when you receive the Terminated message.

One of the possible solutions is take a look into implementation of SupervisorStrategy.Restart. Unfortunately the implementation uses InternalActorRef:
final def restartChild(child: ActorRef, cause: Throwable, suspendFirst: Boolean): Unit = {
val c = child.asInstanceOf[InternalActorRef]
if (suspendFirst) c.suspend()
c.restart(cause)
}
So I assume there is no built-in solution and you should do it yourself.
def receive = {
case Terminated(actorRef) => self ! RestartAll
case RestartAll =>
context.children.foreach(_ ! PoisonPill)
//start all necessary actors again
}

Related

scala akka how to catch ActorInitializationException when using ask pattern

I'm doing something like this:
...lots of surrounding context...
val actor = context.actorOf(Props(new Actor(...))
(actor ? message) onComplete {
case Done => {
println("done")
Do stuff with the surrounding context of this actor
}
case _ => {
println("got wildcard") // try to handle error message here
}
}
Actor is failing at initialization with
akka.actor.ActorInitializationException (in that actors context)
In the parent actor I am getting **dead letters encountered.**
since actor was never created properly and "message" couldn't be delivered.
In this scenario the "ask?" pattern never returns properly.
I could create a SupervisorStrategy in the parent global level, but I need to understand the context of the actor that generated the exception and it isn't possible (or convenient) handling it at the global level
Is there a way to "catch" the initialization exception in the "ask" context actor ? message?
According to akka philosophy ask should be used only when you interact with the actor from the outside of the actor system.
Since you have a reference to the context seems that you are inside the actor code. So you should try to get rid of ask.
If I'm wrong and you call ask from non-akka code then you shouldn't try to rely on anything that happens inside the actor system. All that you have is an ActorRef with no guaranties what is on the other side of this reference.

Capturing the message that killed an actor

I'm trying to respond to the sender of message when the receiving actor dies due to that message. If I Restart the actor on failure I get
preRestart(reason: Throwable, message: Option[Any])
but now I'm committed to restarting.
If I Stop the actor, i only get
postStop()
with no knowledge what stopped myself.
Meanwhile in the supervisor, I only get the Throwable and no indication of what caused it.
I suppose, I can dig through the DeadLetters post actor termination, but that seems like a noisy approach, since I'd have to listen to all of dead letters and somewhere correlate the termination with the deadletter event stream.
UPDATE: DeadLetter really doesn't seem to be an option. The message that caused the death doesn't even go to DeadLetters, it just disappears.
Is there a mechanism I am overlooking?
According to this thread on the Akka Users List, there isn't a mechanism in the actor supervision death cycle to accomplish this. Moreover, the documentation explicitly states that the message is dropped:
What happens to the Message
If an exception is thrown while a message is being processed (i.e. taken out of its mailbox and handed over to the current behavior), then this message will be lost. It is important to understand that it is not put back on the mailbox. So if you want to retry processing of a message, you need to deal with it yourself by catching the exception and retry your flow.
The ideal solution would be to use a dedicated actor for dangerous operations and have the initiator monitor the death of that actor to determine failure.
As my scenario arose from something considered safe but that had a bug in it, the separate actor option would have been after the fact. To avoid wrapping all code paths in try/catch but be able to guard more complicated and critical flows, I ended up with creating a wrapper for receive that let's me intercept exceptions:
object SafeReceive {
def apply(receive: Receive)(recover: Any => PartialFunction[Throwable, Unit]): Receive =
new Receive {
override def isDefinedAt(x: Any): Boolean = receive.isDefinedAt(x)
override def apply(v1: Any): Unit = try {
receive(v1)
} catch recover(v1)
}
}
which I can use for select actors like this:
def receive = SafeReceive {
case ... => ...
} {
msg => {
case e: Exception =>
sender ! OperationFailed(msg, e)
throw e
}
}

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.

Akka - Actor preStart has no previous message

I have some actors that when their preRestart() is invoked, the "message" is None. I don't understand why this is the case.
Context
My application is a Play web application that uses Akka. My error handling strategy is to send an error notification to the origin of the request, so details can be sent down to the user. I do this by hooking into preRestart() as follows:
trait NotifyRequesterErrorHandling { this: Actor with ActorLogging =>
override def preRestart(reason: Throwable, message: Option[Any]) {
notifyRequester(message, reason)
}
protected def notifyRequester(message: Option[Any], reason: Throwable) {
message match {
case Some(m) =>
val who = getRequester(m)
who ! SearchError(reason, m)
case None =>
val error = if (reason == null) "No exception" else reason toString()
ReportError("NotificationError", Some(reason), "", s"${this.context.self.path}: Attempted to notify requester but no previous message")
}
}
def getRequester(message: Any): ActorRef
}
Problem
In my logs, I am seeing a lot of the "Attempted to notify requester but no previous message" error logs. Usually it occurs for all the actors in my system. This is likely because I have one top-level actor, which is responsible for all the other actors (they are all children).
In the logs, the reason parameter does contain a throwable, though.
I am also using a one-for-all strategy. So, basically, whenever all the actors are restarted, I get lots of these errors.
Possible Explanations aka guesses
After all actors are restarted a new instance of each actor is created, and thus there is no previous message
When actors are restarted as one-for-all, all of their messages have been processed and their queue is empty. This means that there is no previous message
The documentation for preRestart states: "message - optionally the current message the actor processed when failing, if applicable"
I.e. it is only applicable to the failing actor. Not the other ones who are just restarted and not failing.

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