Skip to content

Instantly share code, notes, and snippets.

@aarondav
Last active January 6, 2021 17:01
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aarondav/ca1f0cdcd50727f89c0d to your computer and use it in GitHub Desktop.
Save aarondav/ca1f0cdcd50727f89c0d to your computer and use it in GitHub Desktop.
UncaughtExceptionHandler in ActorSystemImpl does not behave as hoped
// Must be in akka.actor package as ActorSystemImpl is protected[akka].
package akka.actor
import java.util.concurrent.TimeUnit
import scala.concurrent.Future
import scala.concurrent.duration.FiniteDuration
import com.typesafe.config.ConfigFactory
/** Intended to provide a custom uncaught exception handler. DOES NOT WORK AS EXPECTED. */
private[akka] class ExceptionCatchingActorSystemImpl(_name: String)
extends ActorSystemImpl(_name, ConfigFactory.empty(), ActorSystem.findClassLoader()) {
println("Custom actor system starting...")
protected override def uncaughtExceptionHandler =
new Thread.UncaughtExceptionHandler() {
def uncaughtException(thread: Thread, cause: Throwable): Unit = {
println("Exception observed:") // not called
cause.printStackTrace()
}
}
}
private object ExceptionCatchingActorSystemTest extends App {
val actorSystem = new ExceptionCatchingActorSystemImpl("MyActorSystem").start()
val actor = actorSystem.actorOf(Props(new TestActor()))
actor ! "Yo"
class TestActor extends Actor {
override def preStart() {
println("Started")
}
override def preRestart(reason: Throwable, message: Option[Any]) {
super.preRestart(reason, message)
println("preRestart called") // not called
}
def receive = {
case "Yo" => {
import context.dispatcher
Future {
throw new Error("Future error")
}
context.system.scheduler.scheduleOnce(new FiniteDuration(1, TimeUnit.MILLISECONDS)) {
throw new Error("Schedule error")
}
Thread.sleep(100)
throw new Error("Akka error")
}
}
}
}
/* Output:
[info] Running akka.actor.ExceptionCatchingActorSystemTest
[info] Custom actor system starting...
[info] Started
[info] [ERROR] [05/09/2014 12:31:35.415] [MyActorSystem-akka.actor.default-dispatcher-2] [TaskInvocation] Schedule error
[info] java.lang.Error: Schedule error
[info] at akka.actor.ExceptionCatchingActorSystemTest$TestActor$$anonfun$receive$1$$anonfun$applyOrElse$2.apply(IndestructibleActorSystem.scala:67)
[info] at akka.actor.ExceptionCatchingActorSystemTest$TestActor$$anonfun$receive$1$$anonfun$applyOrElse$2.apply(IndestructibleActorSystem.scala:67)
[info] at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
[info] at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
[info] at akka.actor.Scheduler$$anon$11.run(Scheduler.scala:118)
[info] at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:42)
[info] at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
[info] at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
[info] at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
[info] at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
[info] at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[info]
[info] [ERROR] [05/09/2014 12:31:35.507] [MyActorSystem-akka.actor.default-dispatcher-3] [LocalActorRefProvider(akka://MyActorSystem)] guardian failed, shutting down system
[info] java.lang.Error: Akka error
[info] at akka.actor.ExceptionCatchingActorSystemTest$TestActor$$anonfun$receive$1.applyOrElse(IndestructibleActorSystem.scala:71)
[info] at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
[info] at akka.actor.ActorCell.invoke(ActorCell.scala:456)
[info] at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
[info] at akka.dispatch.Mailbox.run(Mailbox.scala:219)
[info] at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
[info] at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
[info] at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
[info] at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
[info] at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[info]
[info] [ERROR] [05/09/2014 12:31:35.507] [MyActorSystem-akka.actor.default-dispatcher-3] [akka://MyActorSystem/user] Akka error
[info] java.lang.Error: Akka error
[info] at akka.actor.ExceptionCatchingActorSystemTest$TestActor$$anonfun$receive$1.applyOrElse(IndestructibleActorSystem.scala:71)
[info] at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
[info] at akka.actor.ActorCell.invoke(ActorCell.scala:456)
[info] at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
[info] at akka.dispatch.Mailbox.run(Mailbox.scala:219)
[info] at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
[info] at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
[info] at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
[info] at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
[info] at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
[info]
*/
@longliveenduro
Copy link

I think you did it right, it is just that uncaught exceptions in an Actor's receive doesn't get handled by the uncaught exception handler of the thread, because it is getting handled by the Actor framework before reaching it: https://doc.akka.io/docs/akka/current/fault-tolerance.html

We wanted to change the default uncaught handler of Akka and your gist helped me, thanks: https://stackoverflow.com/questions/65566743/how-do-i-get-the-stacktrace-of-uncaught-exceptions-in-an-akka-actor-system

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment