0

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:

  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.

tribbloid
  • 4,026
  • 14
  • 64
  • 103
  • For the `3.5.x` question, what exactly you want? To run an `IO` until another `IO` completes? Or start an `IO` and get back a `Future` to cancel that `IO`? – Luis Miguel Mejía Suárez Mar 21 '23 at 19:40
  • @LuisMiguelMejíaSuárez given an IO, run it immediately, if it is cancelled after 3 seconds, run the finaliser – tribbloid Mar 21 '23 at 20:14
  • If it is canceled? Or if it hasn't finished? What is the finalizer? something the user provides or cancel the `IO`? And finally, do you want all this on `IO` or outside of `IO`? I mean, this function should return `IO[Unit]` or `Unit`? – Luis Miguel Mejía Suárez Mar 21 '23 at 20:24
  • Yes if it s canceled (I would be glad to know how to handle the similar case when the process is terminated before it is finished, but it may be a different question), the finaliser is the argument of the `runCancelable` function. Since in my example I called `cancelling.unsafeRunSync()` it should return just an `Unit` – tribbloid Mar 21 '23 at 20:34

1 Answers1

0

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

  • Thanks a lot, but do we absolutely have to use Ref for a behaviour that relies on cats-effect 2 IO only? – tribbloid Mar 22 '23 at 18:39
  • @tribbloid well maybe not, I am still sure that what you need is way simpler than the convoluted description you gave _(which is not equivalent to your code at all)_. Anyways, I may suggest asking in the **Discord** server, maybe in chat it would be easier to understand what you really need and hopefully some of the core maintainers may explain way `runCancelable` was removed. – Luis Miguel Mejía Suárez Mar 22 '23 at 18:52
  • SO what are the difference between my code and my description? The code itself was adapted from the example in cats-effect2 scaladoc, and should at least execute the effect `println("SUCCESS!")` – tribbloid Mar 22 '23 at 19:03
  • @tribbloid you said you want to run the finalizer if the effect was not canceled after three seconds, but your code doesn't check that. Rather it just waits three seconds to cancel it and then run the finalizer, in **CE3** that is as simple as `io.timeout(3.seconds).guaranteedCase(finalizer)` – Luis Miguel Mejía Suárez Mar 22 '23 at 20:41
  • @tribbloid also, you want your finalizer to have access to the result of the `io`, but that doesn't make sense since it will run forever and will be canceled, there is no result. Which, is probably the reason you don't see any `println` – Luis Miguel Mejía Suárez Mar 22 '23 at 20:44
  • Ah, I see, let me update it to post the complete version. – tribbloid Mar 22 '23 at 21:37
  • Sorry you are right, it turns out that the argument of "runCancellable" is the continuation callback, not the cancellation callback, the name is quite confusing. – tribbloid Mar 23 '23 at 02:05
  • I'll accept your answer, but since the premise of my question is wrong, I'll ask a new one – tribbloid Mar 23 '23 at 02:06
  • https://stackoverflow.com/questions/75818712/in-cats-effect-what-is-the-safer-alternative-of-io-unsaferuncancelable – tribbloid Mar 23 '23 at 02:06