Here is a short example:
Assuming that forever
is an IO that never ends, I want to run it for 3 seconds and trigger the cancellation:
val start = forever.runCancelable {
case Left(ee) =>
IO {
println(s"FAILUE: ${ee.toString}")
}
case Right(kk) =>
IO {
println("SUCCESS!")
}
}
val cancelling = start.unsafeRunSync()
Thread.sleep(3000)
cancelling.unsafeRunSync()
println("finished")
When this snippet is executed, I found that none of the println cancellation function was executed (neither println and breakpoint works).
As a result, I have 2 questions:
What is the proper way to trigger it? (Including, but limited to, process termination)
(UPDATED) What is the equivalent implementation in cats-effect 3.5.x that is guaranteed to have the same behaviour? runCancelable
is removed in cats-effect 3, there must be a replacement.
I am still not sure if I am completely understanding your requirements but I guess something like this should work:
def runFinalizerAfter[A](program: IO[A], time: FiniteDuration)(finalizer: Option[OutcomeIO[A]] => IO[Unit]): IO[Unit] =
IO.ref(Option.empty[OutcomeIO[A]]).flatMap { ref =>
program.guaranteedCase(outcome => ref.set(Some(outcome))).background.surround {
IO.sleep(time) >> ref.get.flatMap {
case Some(outcome) => finalizer(outcome) // Finished, failed, or cancelled.
case None => IO.unit // Still running.
}
}
}
This cancels the program after running the finalizer.
For making this return
Unit
rather thanIO[Unit]
either justunsafeRunSync
it or use aDispatcher