Skip to content

Instantly share code, notes, and snippets.

@fanf
Created March 10, 2020 12:32
Show Gist options
  • Save fanf/fda33966183f208a40e2b183eef88e65 to your computer and use it in GitHub Desktop.
Save fanf/fda33966183f208a40e2b183eef88e65 to your computer and use it in GitHub Desktop.
Deadlock with ZIO runtime / init in object
object TestRuntime {
object internal {
val platform : _root_.zio.internal.Platform = _root_.zio.internal.Platform.makeDefault()
// a local runtime just to build first zlayer
private val r = Runtime((), platform)
// non memomized env
val env = ZEnv.live
val runtime = Runtime.unsafeFromLayer(env, platform)
// here, everything is fine
runtime.unsafeRun(UIO.effectTotal(println("case 2.1: non blocking")))
runtime.unsafeRun(ZIO.accessM[_root_.zio.blocking.Blocking](_.get.blocking(UIO.effectTotal(println("case 2.2: blocking")))) )
}
def main(args: Array[String]): Unit = {
// in main, this works
{
val platform : _root_.zio.internal.Platform = _root_.zio.internal.Platform.makeDefault()
// a local runtime just to build first zlayer
val r = Runtime((), platform)
val env = ZEnv.live
val runtime = Runtime.unsafeFromLayer(env, platform)
// here, everything is fine
runtime.unsafeRun(UIO.effectTotal(println("case 1.1: non blocking")))
runtime.unsafeRun(ZIO.accessM[_root_.zio.blocking.Blocking](_.get.blocking(UIO.effectTotal(println("case 1.2: blocking")))) )
}
println("done in function, start in object")
// in internal, it blocks
internal
println("done")
/* console output:
case 1.1: non blocking
case 1.2: blocking
done in function, start in object
case 2.1: non blocking
// block forever, thread waiting
"zio-default-blocking-1-555173385@1943" daemon prio=5 tid=0x20 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at com.normation.TestRuntime$internal$$$Lambda$388.1905485420.apply$mcV$sp(Unknown Source:-1) // seems to be "1.2 blocking" effect
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at zio.internal.FiberContext.evaluateNow(FiberContext.scala:383) // curZio = nextInstr(effect())
at zio.internal.FiberContext.$anonfun$evaluateLater$1(FiberContext.scala:679)
at zio.internal.FiberContext$$Lambda$224.1368440436.run(Unknown Source:-1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.lang.Thread.run(Thread.java:834)
*/
}
}
@fanf
Copy link
Author

fanf commented Mar 10, 2020

It may be variant of: zio/zio#1841
But just adding lazy is not sufficient:

object zioRuntime {
  object internal {
    lazy val platform : _root_.zio.internal.Platform = _root_.zio.internal.Platform.makeDefault()
    lazy val environment = {
      // that platform is just for init zlayer
      val r = Runtime((), platform)
      r.unsafeRun(ZEnv.live.build.memoize.map(ZLayer(_)).use(ZIO.succeed(_)))
    }
    lazy val runtime = Runtime.unsafeFromLayer(environment, platform)
    runtime.unsafeRun(UIO.effectTotal(println("**** case 1: non blocking")))
    runtime.unsafeRun(ZIO.accessM[_root_.zio.blocking.Blocking](_.get.blocking(UIO.effectTotal(println("**** case 2: blocking")))).provideLayer(environment) )
    runtime.unsafeRun(_root_.zio.blocking.blocking(UIO.effectTotal(println("**** case 3: blocking variant"))).provideLayer(environment))
  }
}

object TestRuntime {
  def main(args: Array[String]): Unit = {
    zioRuntime.internal.runtime.unsafeRun(UIO.effectTotal(println("**** case 10: non blocking")))
    zioRuntime.internal.runtime.unsafeRun(ZIO.accessM[_root_.zio.blocking.Blocking](_.get.blocking(UIO.effectTotal(println("**** case 20: blocking")))).provideLayer(zioRuntime.internal.environment) )
    zioRuntime.internal.runtime.unsafeRun(_root_.zio.blocking.blocking(UIO.effectTotal(println("**** case 30: blocking variant"))).provideLayer(zioRuntime.internal.environment))
    println("done")
}
``` => blocks in the println #2 in object `internal`

@fanf
Copy link
Author

fanf commented Mar 10, 2020

But that works:

class internalRuntime {
    lazy val platform : _root_.zio.internal.Platform = _root_.zio.internal.Platform.makeDefault()
    lazy val environment = {
      // that platform is just for init zlayer
      val r = Runtime((), platform)
      r.unsafeRun(ZEnv.live.build.memoize.map(ZLayer(_)).use(ZIO.succeed(_)))
    }
    lazy val runtime = Runtime.unsafeFromLayer(environment, platform)
    runtime.unsafeRun(UIO.effectTotal(println("**** case 1: non blocking")))
    runtime.unsafeRun(ZIO.accessM[_root_.zio.blocking.Blocking](_.get.blocking(UIO.effectTotal(println("**** case 2: blocking")))).provideLayer(environment) )
    runtime.unsafeRun(_root_.zio.blocking.blocking(UIO.effectTotal(println("**** case 3: blocking variant"))).provideLayer(environment))
  }

object zioRuntime {
  lazy val internal = new internalRuntime()
}
//same TestRuntime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment