Skip to content

Commit

Permalink
propagate computation failure in timeout utility functions (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
nimatrueway authored Sep 10, 2024
1 parent 26bc45c commit 4ec990f
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 4 deletions.
13 changes: 9 additions & 4 deletions core/src/main/scala/ox/race.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@ import scala.concurrent.TimeoutException
import scala.concurrent.duration.FiniteDuration
import scala.util.{Failure, Success, Try}

/** A `Some` if the computation `t` took less than `duration`, and `None` otherwise. */
/** A `Some` if the computation `t` took less than `duration`, and `None` otherwise. if the computation `t` throws an exception, it is
* propagated.
*/
def timeoutOption[T](duration: FiniteDuration)(t: => T): Option[T] =
race(Some(t), { sleep(duration); None })
raceResult(Some(t), { sleep(duration); None })

/** The result of computation `t`, if it took less than `duration`, and a [[TimeoutException]] otherwise.
/** The result of computation `t`, if it took less than `duration`, and a [[TimeoutException]] otherwise. if the computation `t` throws an
* exception, it is propagated.
* @throws TimeoutException
* If `t` took more than `duration`.
*/
def timeout[T](duration: FiniteDuration)(t: => T): T =
timeoutOption(duration)(t).getOrElse(throw new TimeoutException(s"Timed out after $duration"))

/** Result of the computation `t` if it took less than `duration`, and `Left(timeoutValue)` otherwise. */
/** Result of the computation `t` if it took less than `duration`, and `Left(timeoutValue)` otherwise. if the computation `t` throws an
* exception, it is propagated.
*/
def timeoutEither[E, T](duration: FiniteDuration, timeoutValue: E)(t: => Either[E, T]): Either[E, T] =
timeoutOption(duration)(t).getOrElse(Left(timeoutValue))

Expand Down
27 changes: 27 additions & 0 deletions core/src/test/scala/ox/ControlTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import ox.util.Trail

import scala.concurrent.TimeoutException
import scala.concurrent.duration.DurationInt
import scala.util.Failure
import scala.util.Try

class ControlTest extends AnyFlatSpec with Matchers {
"timeout" should "short-circuit a long computation" in {
Expand All @@ -26,6 +28,14 @@ class ControlTest extends AnyFlatSpec with Matchers {
trail.get shouldBe Vector("timeout", "done")
}

it should "pass through the exception of failed computation" in {
val myException = new Throwable("failed computation")

Try {
timeout(1.second)(throw myException)
} shouldBe Failure(myException)
}

it should "not interrupt a short computation" in {
val trail = Trail()
unsupervised {
Expand Down Expand Up @@ -57,4 +67,21 @@ class ControlTest extends AnyFlatSpec with Matchers {

trail.get shouldBe Vector("done")
}

"timeoutOption" should "pass through the exception of failed computation" in {
val myException = new Throwable("failed computation")

Try {
timeoutOption(1.second)(throw myException)
} shouldBe Failure(myException)
}

"timeoutEither" should "pass through the exception of failed computation" in {
val myException = new Throwable("failed computation")

Try {
timeoutEither(1.second, new TimeoutException(s"Timed out after 1 seconds"))(throw myException)
} shouldBe Failure(myException)
}

}

0 comments on commit 4ec990f

Please sign in to comment.