Closed quelgar closed 2 years ago
This is expected behavior. This is codified in the following test in the "interruption semantics" suite:
test("self-interruption can be averted") {
for {
ref <- Ref.make(false)
fiber <- ZIO.interrupt.catchAllCause(_ => ref.set(true)).fork
_ <- fiber.await
value <- ref.get
} yield assertTrue(value == true)
}
Yes, I'd expect catchAllCause
to catch all causes. But tapDefect
filters out failures and I'd expected it to filter out interruptions too.
I think the Scaladoc of foldCauseZIO
is misleading then? "Except interruptions" should be removed.
/**
* A more powerful version of `foldZIO` that allows recovering from any kind
* of failure except interruptions.
*/
final def foldCauseZIO[R1 <: R, E2, B](
scala> val w = ZIO.interrupt.foldCause(c => s"failure: ${c.isInterrupted}", _ => "success")
val w: zio.URIO[Any, String] = OnSuccessAndFailure(<empty>.rs$line$21$.w.macro(rs$line$21:1),Stateful(<empty>.rs$line$21$.w.macro(rs$line$21:1),zio.ZIO$$$Lambda$1414/0x00000008005e5f28@11476fd1),zio.ZIO$$Lambda$1999/0x00000008007a27d8@14b26bc2,zio.ZIO$$Lambda$1998/0x00000008007a21b8@5ed3696c)
scala> Unsafe.unsafe(Runtime.default.unsafe.run(w))
val res8: zio.Exit[Nothing, String] = Success(failure: true)
A more precise statement would be that foldCauseZIO
allows recovering from any kind of failure except external interruptions. To see this consider the following test:
test("external interruption cannot be recovered from") {
for {
promise <- Promise.make[Nothing, Unit]
ref <- Ref.make(false)
fiber <- ZIO.uninterruptibleMask { restore =>
promise.succeed(()) *> restore(ZIO.never).foldCauseZIO(_ => ref.set(true), _ => ZIO.unit)
}.forkDaemon
_ <- promise.await
exit <- fiber.interrupt
value <- ref.get
} yield assert(value)(isTrue) && assert(exit)(isInterrupted)
}
In this example the fiber is externally interrupted and foldCauseZIO
is able to observe that interruption and act on it assuming it is in an uninterruptible region. This is in fact how ensuring
is implemented. However, foldCauseZIO
cannot recover from the external interruption. Once the fiber is externally interrupted it is in wind down, which can be delayed while the fiber is in an uninterruptible region but can never be recovered from.
Oh I see, thank you for explaining!
Should this test pass?
tapDefect
is built onfoldCauseZIO
, the Scaladoc of which I interpret as meaning interruptions will not be passed to the failure case, but it appears they are passed to it.