-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"fatal" errors are not reported to the ExecutionContext #12152
Comments
@yanns could you update the example to be compilable as-is standalone? it's missing a lot of imports, and you're using several libraries you haven't specified the names and versions of, so that makes unneeded work for anyone who wants to try this themselves |
Here is a standalone version: import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.{ExecutorService, SynchronousQueue, ThreadPoolExecutor, TimeUnit}
import akka.dispatch.ExecutorServiceDelegate
import scala.concurrent.{Await, ExecutionContextExecutorService, Future}
import scala.concurrent.duration._
import scala.util.Try
object Main extends App {
val parentEc = new ThreadPoolExecutor(1, 10, 100, TimeUnit.MILLISECONDS, new SynchronousQueue())
val reportedError = new AtomicReference[Throwable]()
val executionContext = new ExecutorServiceDelegate with ExecutionContextExecutorService {
override def executor: ExecutorService = parentEc
override def reportFailure(cause: Throwable): Unit = reportedError.set(cause)
}
val futureFailingWithFatalError =
Future.unit.map(_ => throw new NoSuchMethodError("test"))(executionContext)
val result = Try(Await.result(futureFailingWithFatalError, 100.millis))
assert(result.isFailure)
// should not be null, but be a NoSuchMethodError("test")
assert(reportedError.get() == null)
// assert(reportedError.get().asInstanceOf[NoSuchMethodError].getMessage == "test")
executionContext.shutdown()
} |
I don't feel so, but I'm not completely sure about it. |
@viktorklang at #9554 you wrote:
is @yanns's example functioning as expected? cc @NthPortal |
@SethTisue Fatal throwables are not reported, because after a fatal error execution is undefined and calling more code after observing one might obscure the "true" fatal exception. So that is bubbled up instead of reported-and-continue-as-usual: https://github.com/scala/scala/blob/2.13.x/src/library/scala/concurrent/impl/Promise.scala#L404 |
I thought it was reported (and apparently past me thought that as well: #9554 (comment)), but perhaps I was mistaken? I do feel it ought to be surfaced somehow, and not just silently swallowed. I know Akka's |
@viktorklang does that mean it gets handled by whatever |
@viktorklang happy to close the ticket, but I would like to understand what the upshot for the user is. is the upshot to use an @NthPortal jinx :-) |
How is it possible for example to stop the JVM is case of fatal exceptions?
From the application perspective, I'm missing a way to react to such exceptions and do something useful, like shutting down the JVM. |
I see that I can use |
I'm trying the following but it does not work:
|
based on what Akka does (https://github.com/akka/akka/blob/a61b4868e06fd8a31a66b3898f75baa24d3a946e/akka-actor/src/main/scala/akka/actor/ActorSystem.scala#L816-L839), I am going to say with more confidence that an |
By default Global uses the default reporter as the UEH: https://github.com/scala/scala/blob/2.13.x/src/library/scala/concurrent/impl/ExecutionContextImpl.scala#L99 so yes, UncaughtExceptionHandler is the way to go. |
To be honest, I'm not completely satisfied with the proposed solution. Let me explain the context: we have servers handling lot of requests. For those requests, as the For the proposed solution, we can stop the server when such issues happen. Having a |
@yanns Typically NoSuchMethodError indicates that the classpath is broken—and as such the most appropriate default way of handling that is to exit the process as fast as possible. If you have cases where this is a normal situation, there's nothing which prevents you from adding a regular |
I've tried that approach, but it is not possible to put a try / catch everywhere. Our main abstraction is I've tried to put that in the execution context, but it also does not work:
My preferred option now is to add monitoring on |
Putting it everywhere would defeat the purpose—you should put it in the places where getting a NSME is a system-reasonable place to put it (or rather, where you allow it to occur). Catching it everywhere means that you could get NSMEs for reasons which are not safe to catch. So I think the appropriate to do is to analyze when/where NSMEs are to be expected in your codebase and put the try-catches there, while documenting why this is sound at that place. Wrapping the Runnable won't work, as you discovered, since things are already "unrecoverable" at that point. |
(follow up of #12150)
reproduction steps
using Scala 2.13.3,
the following scala test:
is failing with:
problem
The
NoSuchMethodError
should be reported to theexecutionContext
The text was updated successfully, but these errors were encountered: