scala akka how to catch ActorInitializationException when using ask pattern - scala

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.

Related

Is it safe to override `receive` in an Akka FSM?

I created an FSM with Akka. However, my FSM doesn't only get messages passed that are relevant for its FSM state. Its children may also pass ActorRefs up to it, which my FSM should then pass further up to its parent. Since FSMs in Akka are (naturally) also actors, I would like to override receive to catch those ActorRefs. However, doing that broke the FSM functionality of the actor. What's the proper way to handle a situation like this?
Messages that are not relevant for any FSM state can be handled in whenUnhandled:
whenUnhandled {
case Event(someActorRef: ActorRef, _) =>
context.parent ! someActorRef
stay()
}
Though, overriding receive should, afaik, work, too.

Sending back to sender, from supervisor, in case of failure

I have an Actor, which acts as a Supervisor, but also needs to "return" data to the caller, wether this is an actor or not shouldn't matter.
I am asking my Supervisor, let's call him SV.
SV Processes the message I send to him, and sends back a response.
val system = ActorSystem("ActorSystem")
val sv = system.actorOf(Props[SV], name = "SV")
sv ? msg
And SV's recieve method looks like this:
def receive = {
case msg => (someChild ? msg).pipeTo(sender)
...
}
This all works jolly fine.
The problem is when the child throws an exception, this exception is caught by the supervisor strategy.
override def supervisorStrategy = OneForOneStrategy () {
case e : Throwable => {
val newResponse = someNewResponse
sender ! newResponse
...
}
}
sender is not longer a reference to whoever called SV in the first place, and I can't seem to work out how to send a message back to the askee, and get back to my original flow.
One of the three Actor rules is: “An Actor can send a finite number of messages to other Actors it knows.” The last two words are critical here: if the supervisor has not been introduced to the original sender somehow and the failure (exception) itself does not contain the sender’s reference either, then the supervisor cannot possibly send a message to the sender. Either you catch all exceptions in the child actor, wrap them together with the sender in your own exception type and then rethrow, or the original message needs to travel via the supervisor to the child and back, so that the supervisor can see that a reply is outstanding when a failure occurs.
Are you using the supervisor strategy and exceptions to control the flow or your data? Consider using the type system (Option type or a Failure on the response Future) for "exception" cases in your child actors and handle the response flow without exceptions.
The supervisor strategy is for unhandled exceptions.
When an unhandled exception occurs you lose the ability to respond with a message to the sender. Unless you wrap the sender in the unhandled exception like Roland Kuhn suggests.
Let the supervisor strategy instead handle how the actor system should respond to your unhandled exceptions by mapping them to a Directive.

Akka - How to handle termination

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
}

When is supervisor strategy called?

When is the supervisor strategy invoked ? Is it when the exception is thrown for an Actor. In below code :
#Override
public SupervisorStrategy supervisorStrategy() {
System.out.println("supervisorStrategy");
return strategy;
}
The println statement is not invoked when actor is created. Is this expected behaviour ?
Unlike the not-to-well-named receive method, which is only called during Actor initialization to acquire the PartialFunction that will handle incoming messages, the supervisorStrategy method is used when failures occur. It is a regular method that does the work of deciding how to handle a failure in a descendant Actor.
Hmm... I just noticed you're using Java, so the part about receive is presumably different for you, but the supervisorStrategy statement still applies.

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