diff --git a/core/jvm/src/main/scala/cats/effect/IOApp.scala b/core/jvm/src/main/scala/cats/effect/IOApp.scala index 6939dd9f0b..44a6ef901e 100644 --- a/core/jvm/src/main/scala/cats/effect/IOApp.scala +++ b/core/jvm/src/main/scala/cats/effect/IOApp.scala @@ -568,12 +568,7 @@ trait IOApp { r.run() } catch { case t if NonFatal(t) => - if (isForked) { - t.printStackTrace() - System.exit(1) - } else { - throw t - } + IOApp.this.reportFailure(t).unsafeRunAndForgetWithoutCallback()(runtime) case t: Throwable => t.printStackTrace() diff --git a/ioapp-tests/src/test/scala/IOAppSpec.scala b/ioapp-tests/src/test/scala/IOAppSpec.scala index 11527ae72c..94b8c19e62 100644 --- a/ioapp-tests/src/test/scala/IOAppSpec.scala +++ b/ioapp-tests/src/test/scala/IOAppSpec.scala @@ -354,6 +354,11 @@ class IOAppSpec extends Specification { h.awaitStatus() mustEqual 0 } + "use configurable reportFailure for runnables on MainThread" in { + val h = platform("MainThreadReportFailureRunnable", List.empty) + h.awaitStatus() mustEqual 0 + } + "warn on blocked threads" in { val h = platform("BlockedThreads", List.empty) h.awaitStatus() diff --git a/tests/jvm/src/main/scala/catseffect/examplesplatform.scala b/tests/jvm/src/main/scala/catseffect/examplesplatform.scala index c7a6396b8f..882829399f 100644 --- a/tests/jvm/src/main/scala/catseffect/examplesplatform.scala +++ b/tests/jvm/src/main/scala/catseffect/examplesplatform.scala @@ -71,6 +71,19 @@ package examples { } + object MainThreadReportFailureRunnable extends IOApp { + + val exitCode = new AtomicReference[ExitCode](ExitCode.Error) + + override def reportFailure(err: Throwable): IO[Unit] = + IO(exitCode.set(ExitCode.Success)) + + def run(args: List[String]): IO[ExitCode] = + IO(MainThread.execute(() => throw new Exception)) *> + IO.sleep(1.second) *> IO(exitCode.get) + + } + object BlockedThreads extends IOApp.Simple { override protected def blockedThreadDetectionEnabled = true