Skip to content

Commit 2a6baea

Browse files
authored
Add other exceptions from race as suppressed (#100)
1 parent cd611af commit 2a6baea

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

core/src/main/scala/ox/race.scala

+8-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,14 @@ def race[E, F[_], T](em: ErrorMode[E, F])(fs: Seq[() => F[T]]): F[T] =
3737

3838
@tailrec
3939
def takeUntilSuccess(failures: Vector[Either[E, Throwable]], left: Int): F[T] =
40-
if left == 0 then failures.headOption.getOrElse(throw new NoSuchElementException).fold(em.pureError, throw _)
40+
if left == 0 then
41+
val otherExceptions = failures.tail.collect { case Right(e) => e }
42+
failures.headOption.getOrElse(throw new NoSuchElementException) match
43+
case Left(appError) =>
44+
otherExceptions.foldLeft(em.pureError(appError))(em.addSuppressed)
45+
case Right(e) =>
46+
otherExceptions.foreach(ee => if e != ee then e.addSuppressed(ee))
47+
throw e
4148
else
4249
result.take() match
4350
case Success(v) =>

core/src/test/scala/ox/RaceTest.scala

+18
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,24 @@ class RaceTest extends AnyFlatSpec with Matchers {
113113
end - start should be < 1000L
114114
}
115115

116+
it should "add other exceptions as suppressed" in {
117+
try
118+
race(
119+
throw new RuntimeException("boom1!"), {
120+
Thread.sleep(200)
121+
throw new RuntimeException("boom2!")
122+
}, {
123+
Thread.sleep(200)
124+
throw new RuntimeException("boom3!")
125+
}
126+
)
127+
fail("Race should throw")
128+
catch
129+
case e: Exception =>
130+
e.getMessage shouldBe "boom1!"
131+
e.getSuppressed.map(_.getMessage).toSet shouldBe Set("boom2!", "boom3!")
132+
}
133+
116134
"raceEither" should "return the first successful computation to complete" in {
117135
val trail = Trail()
118136
val start = System.currentTimeMillis()

0 commit comments

Comments
 (0)