[WIP] Using cats.effect.Resource in jupyter (almond) notebook
cats.effect.Resource
provides mehtod use
to interact with some resource.
But there are resources that need to be used not only within one method.
It is more convenient to define some resource in the notebook in place and hope it frees itself when the kernel stops
I couldn’t find the generally accepted solution and wrote my own. The code is self-contained, all imports are included.
import $ivy.`org.typelevel::cats-effect:2.1.3`
import cats.effect._
import cats.effect.concurrent.Deferred
import cats.effect.concurrent.MVar
import scala.concurrent.ExecutionContext
import java.util.concurrent.Executors
import cats.implicits._
val blockingPool =
ExecutionContext.fromExecutor(Executors.newFixedThreadPool(5))
// or scala.concurrent.ExecutionContext.global
implicit val cs: ContextShift[IO] = IO.contextShift(blockingPool)
def resourceDefer[F[_]: Concurrent: ContextShift, A](
resource: Resource[F, A]): F[(Either[Throwable, A], Deferred[F, Unit])] =
for {
deferred <- Deferred[F, Unit]
mvar <- MVar.empty[F, Either[Throwable, A]]
_ <- Concurrent[F].start(
resource
.use(r => mvar.put(r.asRight).flatMap(_ => deferred.get))
.recoverWith(e => mvar.put(e.asLeft).flatMap(_ => deferred.get))
)
resourceAcquired <- mvar.read
} yield (resourceAcquired, deferred)
def resourceUseInAlmondBackground[A](resource: Resource[IO, A]): A =
resourceDefer[IO, A](resource).map {
case (Right(r), deferred) =>
interp.beforeExitHooks += { _ =>
deferred.complete().unsafeRunSync
}
r
case (Left(e), _) => throw e
}.unsafeRunSync