Cancelation hangs in `Dispatcher#unsafeToFutureCancelable`
armanbilge opened this issue · 2 comments
armanbilge commented
h/t @TimWSpence for original minimization.
//> using scala "3.3.1"
//> using dep "org.typelevel::cats-effect::3.5.2"
import cats.*
import cats.syntax.all.*
import cats.effect.*
import cats.effect.std.Dispatcher
import scala.concurrent.duration.*
object Repro extends IOApp.Simple:
// also sequential
val run = Dispatcher.parallel[IO].use { dispatcher =>
IO.fromFuture {
IO {
println("starting")
val (_, cancel) = dispatcher.unsafeToFutureCancelable(IO.never) // broken
// val (_, cancel) = IO.never.unsafeToFutureCancelable()(runtime) // works
println("started, now canceling")
cancel()
}
}.flatMap(_ => IO(println("canceled"))).replicateA_(1000)
}
durban commented
There are (at least) two different problems here. #3900 seems to fix the problem for Dispatcher.parallel
.
For Dispatcher.sequential
, the problem seems to be that it doesn't actually fork the submitted action, so it can't really cancel it (https://github.com/typelevel/cats-effect/blob/series/3.x/std/shared/src/main/scala/cats/effect/std/Dispatcher.scala#L214). I'm not sure what to do with that.
armanbilge commented
If I remember correctly, a sequential
dispatcher involves at least two fibers:
- a worker fiber, that actually runs tasks
- a supervisor fiber, that restarts the worker if the task it is running (self-)cancels
So even though the task is not actually forked, it should be possible to cancel it by simply canceling the worker fiber.