Created
March 10, 2020 12:32
-
-
Save fanf/fda33966183f208a40e2b183eef88e65 to your computer and use it in GitHub Desktop.
Deadlock with ZIO runtime / init in object
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
*/ | |
} | |
} |
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`
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
Well, it seems to be more complex than that. It works in unit test, but not in real app, so something may be related to other init order.