-
-
Notifications
You must be signed in to change notification settings - Fork 564
Closed
Description
If a fiber is successfully started (via start or supervise), I'd naturally expect it's finalizers (guarantee, guaranteeCase) to be guaranteed to execute. That's not what happens.
By successfully started, I mean that the respective effect, start or supervise, completed successfully.
Reproduction
Cats Effect version: 3.6.3
Below are reproductions using both
start(seeobject StartAndCancel), andSupervisor#supervise(seeobject SupervisorRelease)
to start fibers.
import cats.effect.std.Supervisor
import cats.effect.{ExitCode, IO, IOApp, Ref}
object StartAndCancel extends FiberFinalizationTest {
override def startAndCancelTask(task: IO[Unit]): IO[Unit] =
task
.start
.flatMap(_.cancel) // since `start` completed, `task` finalizers should run, but sometimes don't
}
object SupervisorRelease extends FiberFinalizationTest {
override def startAndCancelTask(task: IO[Unit]): IO[Unit] =
Supervisor[IO]
.use { supervisor =>
supervisor.supervise(task)
} // since `supervise` completed, `task` finalizers should run, but sometimes don't
.void
}
abstract class FiberFinalizationTest extends IOApp {
def startAndCancelTask(task: IO[Unit]): IO[Unit]
override def run(args: List[String]): IO[ExitCode] =
runTestN(100)
.as(ExitCode.Success)
private def runTestN(n: Int): IO[Unit] =
runTest
.parReplicateA(n)
.flatMap { results =>
val succeededCount = results.count(_ == true)
val failedCount = results.count(_ == false)
IO.println(s"Succeeded $succeededCount, failed $failedCount.")
}
private def runTest: IO[Boolean] =
for {
ref <- Ref[IO].of(0)
_ <- startAndCancelTask(mkTask(ref))
result <- ref.get
} yield result == 3
private def mkTask(ref: Ref[IO, Int]): IO[Unit] =
IO
.unit
.guarantee(ref.update(_ + 1))
.guaranteeCase(_ => ref.update(_ + 2))
}Output
When running the above two programs, I get
StartAndCancel
Succeeded 0, failed 100.
I.e. all 100 runs failed to execute finalizers.
SupervisorRelease
Succeeded 61, failed 39.
I.e. 39 out of 100 runs failed to execute finalizers.
Metadata
Metadata
Assignees
Labels
No labels