How to catch an exception within loop/react of an actor? - scala

Is it possible to catch an exception raised within behaviour? Where to place the try/catch? I know that react uses exceptions to reuse the same thread for different actors and that´s why I don´t know where to put the try/catch. I want to catch certain exceptions by myself for logging.
import scala.actors._
def behaviour: PartialFunction[Any,Unit] = {
case x =>
println(x)
throw new IllegalStateException
}
val a = new Actor {
def act {
loop {
react {
behaviour
}
}
}
}
a.start
a ! "Bam"

eThe Actor has a exception handler function which can be overridden:
override def exceptionHandler = {
case e: Exception =>
println(e.getMessage())
}
Whenever a exception is raised in the actor that would normally cause it to terminate - the exceptionHandler partial function is applied to the exception.
Edit
With Exception filter:
class ExceptionalActor extends Actor{
def act() {
loop {
react {
case "bad" => throw new NoSuchFieldException("Bad Message")
case "impossible" => throw new Exception("Impossible Exception")
case m => println("non-bad message " + m )
}
}
}
override def exceptionHandler = {
case e: NoSuchFieldException => println("handled " + e.getMessage() )
}
}
object Tester extends App {
val eActr = new ExceptionalActor
eActr start
eActr ! "any message1"
eActr ! "bad"
eActr ! "any message2"
eActr ! "impossible"
eActr ! "any message3"
}
produces:
non-bad message any message1
handled Bad Message
non-bad message any message2
org.scratch.act.ExceptionalActor#7f5663a2: caught java.lang.Exception: Impossible Exception
:
And actor death.
ref: Actors in Scala

Related

Is it possible for the supervisor to pass the exception to the calling actor if the child actor fails even after retrying N times?

I have two actors Computer and Printer. Computer is the parent of Printer and has a one for one strategy defined for Printer.
I have listed the code below.
class Computer extends Actor with ActorLogging{
import Computer._
import Printer._
implicit val timeout: Timeout = 2 seconds
val printer: ActorRef = context.actorOf(Props[Printer], "printer-actor")
override def receive: Receive = {
case Print(text) => {
val printJob: Future[Any] = printer ? PrintJob(Random.nextInt, text)
printJob.mapTo[Page].map {
case Page(text) => {
log.info(s"Received page containing text ${text}")
context.system.shutdown()
}
}.onFailure {
case t: Throwable => sender ! akka.actor.Status.Failure(t)
}
}
}
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 1 minute) {
case e : Exception => {
log.info(s"caught exception of type ${e.getClass}")
SupervisorStrategy.Restart
}
}
}
class Printer extends Actor with ActorLogging{
import Printer._
override def receive: Receive = {
case PrintJob(id, text) => {
log.info(s"Received ${PrintJob(id, text)}")
if (Random.nextBoolean) sender ! Page(text)
else throw new NoPaperException(id)
}
}
override def preRestart(cause: Throwable, message: Option[Any]) = {
log.info(s"Restarting actor ${self} because of ${cause}. Queueing message ${message}")
postStop()
message.map(self forward _)
}
}
The Printer throws an exception based on the random generator. The code works fine, the supervisor restarts the and retries the child actor on failure just as instructed.
However the ask pattern val printJob: Future[Any] = printer ? PrintJob(Random.nextInt, text) fails with a AkkaTimeoutException in case all attempts to get the Printer actor work fails.
Is there a way to pass back the exact exception which caused the actor to fail ? In this case NoPapperException.
Cheers,
Utsav
to pass the exception back to the sender you need to sender ! Status.Failure(e) - where e is the exception
You can either do that directly from the actor, or if you want to do that from the supervisor you need to have a subclass of exception that would hold the sender ref with it so that the supervisor would be able to send the exception back

How to catch the exceptions thrown inside an actor?

In my actor, the methods may throw exception:
class ServerActor extends Actor {
override def receive: Receive = {
case "Start" =>
println("### actor started")
throw new Exception("My exception when starting")
case msg =>
println("### actor get other message: " + msg)
throw new Exception("another exception for other messages: " + msg)
}
}
Is there any way to handle all the exception in a single place? I want to handle them together, e.g. logging them
Well you can try to do this in parent under supervision strategy:
http://doc.akka.io/docs/akka/snapshot/scala/fault-tolerance.html
Or you have this method on actor:
def preRestart(reason: Throwable, message: Option[Any]): Unit
where reason is the exception that caused the actor to crash.

Resolving Akka futures from ask in the event of a failure

I am calling an Actor using the ask pattern within a Spray application, and returning the result as the HTTP response. I map failures from the actor to a custom error code.
val authActor = context.actorOf(Props[AuthenticationActor])
callService((authActor ? TokenAuthenticationRequest(token)).mapTo[LoggedInUser]) { user =>
complete(StatusCodes.OK, user)
}
def callService[T](f: => Future[T])(cb: T => RequestContext => Unit) = {
onComplete(f) {
case Success(value: T) => cb(value)
case Failure(ex: ServiceException) => complete(ex.statusCode, ex.errorMessage)
case e => complete(StatusCodes.InternalServerError, "Unable to complete the request. Please try again later.")
//In reality this returns a custom error object.
}
}
This works correctly when the authActor sends a failure, but if the authActor throws an exception, nothing happens until the ask timeout completes. For example:
override def receive: Receive = {
case _ => throw new ServiceException(ErrorCodes.AuthenticationFailed, "No valid session was found for that token")
}
I know that the Akka docs say that
To complete the future with an exception you need send a Failure message to the sender. This is not done automatically when an actor throws an exception while processing a message.
But given that I use asks for a lot of the interface between the Spray routing actors and the service actors, I would rather not wrap the receive part of every child actor with a try/catch. Is there a better way to achieve automatic handling of exceptions in child actors, and immediately resolve the future in the event of an exception?
Edit: this is my current solution. However, it's quite messy to do this for every child actor.
override def receive: Receive = {
case default =>
try {
default match {
case _ => throw new ServiceException("")//Actual code would go here
}
}
catch {
case se: ServiceException =>
logger.error("Service error raised:", se)
sender ! Failure(se)
case ex: Exception =>
sender ! Failure(ex)
throw ex
}
}
That way if it's an expected error (i.e. ServiceException), it's handled by creating a failure. If it's unexpected, it returns a failure immediately so the future is resolved, but then throws the exception so it can still be handled by the SupervisorStrategy.
If you want a way to provide automatic sending of a response back to the sender in case of an unexpected exception, then something like this could work for you:
trait FailurePropatingActor extends Actor{
override def preRestart(reason:Throwable, message:Option[Any]){
super.preRestart(reason, message)
sender() ! Status.Failure(reason)
}
}
We override preRestart and propagate the failure back to the sender as a Status.Failure which will cause an upstream Future to be failed. Also, it's important to call super.preRestart here as that's where child stopping happens. Using this in an actor looks something like this:
case class GetElement(list:List[Int], index:Int)
class MySimpleActor extends FailurePropatingActor {
def receive = {
case GetElement(list, i) =>
val result = list(i)
sender() ! result
}
}
If I was to call an instance of this actor like so:
import akka.pattern.ask
import concurrent.duration._
val system = ActorSystem("test")
import system.dispatcher
implicit val timeout = Timeout(2 seconds)
val ref = system.actorOf(Props[MySimpleActor])
val fut = ref ? GetElement(List(1,2,3), 6)
fut onComplete{
case util.Success(result) =>
println(s"success: $result")
case util.Failure(ex) =>
println(s"FAIL: ${ex.getMessage}")
ex.printStackTrace()
}
Then it would properly hit my Failure block. Now, the code in that base trait works well when Futures are not involved in the actor that is extending that trait, like the simple actor here. But if you use Futures then you need to be careful as exceptions that happen in the Future don't cause restarts in the actor and also, in preRestart, the call to sender() will not return the correct ref because the actor has already moved into the next message. An actor like this shows that issue:
class MyBadFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
def receive = {
case GetElement(list, i) =>
val orig = sender()
val fut = Future{
val result = list(i)
orig ! result
}
}
}
If we were to use this actor in the previous test code, we would always get a timeout in the failure situation. To mitigate that, you need to pipe the results of futures back to the sender like so:
class MyGoodFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
import akka.pattern.pipe
def receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut pipeTo sender()
}
}
In this particular case, the actor itself is not restarted because it did not encounter an uncaught exception. Now, if your actor needed to do some additional processing after the future, you can pipe back to self and explicitly fail when you get a Status.Failure:
class MyGoodFutureUsingActor extends FailurePropatingActor{
import context.dispatcher
import akka.pattern.pipe
def receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut.to(self, sender())
case d:Double =>
sender() ! d * 2
case Status.Failure(ex) =>
throw ex
}
}
If that behavior becomes common, you can make it available to whatever actors need it like so:
trait StatusFailureHandling{ me:Actor =>
def failureHandling:Receive = {
case Status.Failure(ex) =>
throw ex
}
}
class MyGoodFutureUsingActor extends FailurePropatingActor with StatusFailureHandling{
import context.dispatcher
import akka.pattern.pipe
def receive = myReceive orElse failureHandling
def myReceive:Receive = {
case GetElement(list, i) =>
val fut = Future{
list(i)
}
fut.to(self, sender())
case d:Double =>
sender() ! d * 2
}
}

Akka supervisor actor do not handle exception when child actor throws an exception within onFailure of a future

I'm facing a problem with an Akka supervisor actor. When the child actor throws an exception within onFailure method of a future result, the supervisor does not handle the error (I want to restart the child in the case of a ConnectException).
I'm using Akka 2.3.7.
This is the supervisor actor:
class MobileUsersActor extends Actor with ActorLogging {
import Model.Implicits._
import Model.MobileNotifications
override val supervisorStrategy =
OneForOneStrategy(maxNrOfRetries = 3, withinTimeRange = 1 minute) {
case _: java.net.ConnectException => {
Logger.error("API connection error. Check your proxy configuration.")
Restart
}
}
def receive = {
case Start => findMobileUsers
}
private def findMobileUsers = {
val notis = MobileNotificationsRepository().find()
notis.map(invokePushSender)
}
private def invokePushSender(notis: List[MobileNotifications]) = {
notis.foreach { n =>
val pushSender = context.actorOf(PushSenderActor.props)
pushSender ! Send(n)
}
}
}
And this is the child actor:
class PushSenderActor extends Actor with ActorLogging {
def receive = {
case Send(noti) => {
val response = sendPushNotification(noti) onFailure {
case e: ConnectException => throw e
}
}
}
private def sendPushNotification(noti: MobileNotifications): Future[WSResponse] = {
val message = "Push notification message example"
Logger.info(s"Push Notification >> $message to users " + noti.users)
PushClient.sendNotification(message, noti.users)
}
}
I tried to notify sender with an akka.actor.Status.Failure(e) as is suggested here, but did not work, the exception keep unhandled by the supervisor.
As a workaround, I found this way to get it work:
class PushSenderActor extends Actor with ActorLogging {
def receive = {
case Send(noti) => {
val response = sendPushNotification(noti) onFailure {
case e: ConnectException => self ! APIConnectionError
}
}
case APIConnectionError => throw new ConnectException
}
private def sendPushNotification(noti: MobileNotifications): Future[WSResponse] = {
val message = "Push notification message example"
Logger.info(s"Push Notification >> $message to users " + noti.users)
PushClient.sendNotification(message, noti.users)
}
}
Is this an Akka bug or am I doing something wrong?
Thanks!
I think that the problem is that the exception thrown inside the Future doesn't belong to the same thread (potentially) as the one the Actor is running (someone more experienced can elaborate on this). So, the problem is that the exception thrown inside the Future body is "swallowed" and not propagated to the Actor. Since this is the case, the Actor doesn't fail and so there's no need to apply the supervision strategy. So, the first solution that comes to my mind is to wrap the exception inside the Future in some message, send it to yourself, and then throw it from inside the Actor context itself. This time, the Exception will be caught and the supervision strategy will be applied. Note, however, that unless you send the Send(noti) message again, you will not see the Exception happening since the Actor was restarted. All in all, the code would be like this:
class PushSenderActor extends Actor with ActorLogging {
case class SmthFailed(e: Exception)
def receive = {
case Send(noti) => {
val response = sendPushNotification(noti) onFailure {
case e: ConnectException => self ! SmthFailed(e) // send the exception to yourself
}
}
case SmthFailed(e) =>
throw e // this one will be caught by the supervisor
}
private def sendPushNotification(noti: MobileNotifications): Future[WSResponse] = {
val message = "Push notification message example"
Logger.info(s"Push Notification >> $message to users " + noti.users)
PushClient.sendNotification(message, noti.users)
}
}
Hope it helped.

How should an akka actor be created that might throw an exception?

I am migrating a project from scala actors to akka actors. I used to have something like this where the constructor of MyActor may throw an exception if a certain system resource is unavailable:
var myActor: MyActor = null
try {
myActor = new MyActor(3)
}
catch {
case e: SomeUserDefinedException => println("failed!")
}
With akka, I migrated the code to this:
val someParam = 3
var myActor: ActorRef = null
try {
myActor = context.actorOf(Props(classOf[MyActor], someParam), "myActor")
}
catch {
case e: SomeUserDefinedException => println("failed!")
}
The problem I'm having is that it seems like in the akka case, the context.actorOf call isn't actually creating the MyActor object itself, but deferring it to another thread. So when the constructor throws an exception, the try/catch block that I put in has no effect.
How can I migrate this scala actor code into akka actors? Ideally I would prefer to avoid adding a lot of additional complexity.
You can catch the exception in the constructor of MyActor and notify other actors (e.g. the parent) about this exception. Try this:
class MyActor(val parent: ActorRef) extends Actor {
try{
throw new RuntimeException("failed construct")
} catch {
case e: Throwable =>
parent ! e
throw e
}
def receive: Actor.Receive = {case _ => }
}
class ParentActor extends Actor {
val child = context.actorOf(Props(classOf[MyActor], self), "child")
override def receive = {
case e: Throwable => println(e)
}
}