diff --git a/README.md b/README.md index 89c9270..09be81e 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,10 @@ Multiple `Managed` instances are composed or stacked via `flatMap`, generally wi Once the `Managed` stack is composed, the underlying resources are built and used with `use` or `useUntilShutdown`. Setup occurs in the order of the for comprehension or `flatMap`s, and teardown happens in the reverse order. -Exception behavior is as follows: +Non-fatal exceptions are handled as follows: - Exceptions during setup are thrown after already-built resources are torn down - Exceptions during usage are thrown after resources are torn down -- Exceptions during teardown are thrown, but only after teardown is called on every resource. +- Exceptions during teardown are thrown, but only after teardown is called on every resource. - If an exception is thrown during usage, and an additional exception occurs during teardown, the usage exception is thrown with the teardown exception added as a suppressed exception. - If an exception is thrown during setup, and an additional exception occurs during teardown, the setup exception is thrown with the teardown exception added as a suppressed exception. diff --git a/managerial/src/main/scala/ca/dvgi/managerial/Managed.scala b/managerial/src/main/scala/ca/dvgi/managerial/Managed.scala index ecd361d..4d4160c 100644 --- a/managerial/src/main/scala/ca/dvgi/managerial/Managed.scala +++ b/managerial/src/main/scala/ca/dvgi/managerial/Managed.scala @@ -3,6 +3,7 @@ package ca.dvgi.managerial import scala.util.Try import scala.util.Failure import scala.util.Success +import scala.util.control.NonFatal /** An instance of Managed wraps a resource and manages its lifecycle. * @@ -22,14 +23,14 @@ trait Managed[+T] { selfT => var toThrow: Throwable = null try f(r.get) catch { - case t: Throwable => + case NonFatal(t) => toThrow = t null.asInstanceOf[R] // compiler doesn't know that finally will throw } finally { try { r.teardown() } catch { - case t: Throwable => + case NonFatal(t) => if (toThrow == null) toThrow = t else toThrow.addSuppressed(t) } @@ -47,8 +48,8 @@ trait Managed[+T] { selfT => * or teardown. By default, exceptions on setup or teardown are thrown. */ def useUntilShutdown( - onSetupException: PartialFunction[Throwable, Unit] = { case t: Throwable => throw t }, - onTeardownException: PartialFunction[Throwable, Unit] = { case t: Throwable => throw t } + onSetupException: PartialFunction[Throwable, Unit] = { case NonFatal(t) => throw t }, + onTeardownException: PartialFunction[Throwable, Unit] = { case NonFatal(t) => throw t } ): Unit = { var r: Resource[T] = null @@ -75,11 +76,11 @@ trait Managed[+T] { selfT => try { f(t.get).build() } catch { - case setupThrowable: Throwable => + case NonFatal(setupThrowable) => try { t.teardown() } catch { - case teardownThrowable: Throwable => + case NonFatal(teardownThrowable) => setupThrowable.addSuppressed(teardownThrowable) }