I want that user can run a timer with callback and able to cancel it. Something like this:
def main: F[Unit] =
for
cancel <- runTimer(callback, 5.seconds)
shouldCancel <- askUser
_ <- cancel.whenA(shouldCancel)
yield ()
How can I do it in terms of Cats of FS2?
The code that you need is actually pretty simple thanks to cats-effect being very powerful at solving concurrency problems:
def runTimer(
callback: IO[Unit],
delay: Duration,
cancel: IO[Unit]
): IO[Unit] =
IO.race(
IO.sleep(delay) >> callback.uncancelable,
cancel
).void
The key aspects are as follows:
IO.sleep
to delay the execution of the callback.uncancelable
to make the callback uncancelable.IO.race
to run both the delayed callback and the cancel concurrently. If the cancel
completes before the delay, the race
will cancel the execution of the callback.You could improve this to ensure that
cancel
can't cancel thecallback
, but allow an upper cancellation to cancel the wholerace
.
You can see a demo of the code running here: https://scastie.scala-lang.org/BalmungSan/UP6N6wMBTQGLHPjOmXS9mw/1