import cats.effect.Clock import cats.effect.{IOApp, Resource, IO, ResourceApp, ExitCode} import scala.concurrent.duration._ object Dummy extends IOApp { val resource = Resource.make(IO(System.currentTimeMillis)){ start => IO.sleep(3.seconds) >> IO.println(s"Exiting -- ${System.currentTimeMillis - start}") } def run(args: List[String]) = resource.use { ctx => val interruptible = IO.never for { _ <- IO.println(s"Running -- $ctx") start <- Clock[IO].monotonic // _ <- IO.sleep(10.seconds) // this one exits early: resource cleanup time + elapsed time so far _ <- IO.never.race(IO.blocking { Thread.sleep(10000) }) // this one hangs until completion finish <- Clock[IO].monotonic _ <- IO.println(s"Done running... ${(finish - start).toMillis}") } yield ExitCode.Success } } // SBT setting: // Compile / run / fork := true // ctrl-C with SBT: exits to SBT console immediately, // With sleep: // [info] running (fork) com.example.Dummy // [info] Running -- 1630021681166 // ^C // [warn] Canceling execution... // [error] Total time: 1 s, completed Aug 26, 2021 4:48:01 PM // sbt:exporter> [info] Exiting -- 3544 // With blocking: // [info] running (fork) com.example.Dummy // [info] Running -- 1630021764778 // ^C // [warn] Canceling execution... // [error] Total time: 2 s, completed Aug 26, 2021 4:49:26 PM // sbt:exporter> [info] Exiting -- 13052 // without "fork" enabled, you _also_ get the "Done running" output, // signaling that nothing is actually getting interrupted