In Scala library cats-effect 2, how to reliably trigger an IO cancelling?

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 {

    val cancelling = start.unsafeRunSync()




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:

  1. What is the proper way to trigger it? (Including, but limited to, process termination)

  2. (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.


  • For CE3

    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 than IO[Unit] either just unsafeRunSync it or use a Dispatcher