zio / zio

ZIO — A type-safe, composable library for async and concurrent programming in Scala
https://zio.dev
Apache License 2.0
4.08k stars 1.28k forks source link

simple ammonite script does not work with zio #4806

Open domdorn opened 3 years ago

domdorn commented 3 years ago

script.sc

import $ivy.`dev.zio::zio:1.0.5`
import zio._

val program = for {
  _ <- zio.console.putStrLn("starting zio program")
} yield ()

println("should run program now")
println(program)
println()
zio.Runtime.default.unsafeRun(program.provideLayer(zio.ZEnv.live)) // here it just blocks and does nothing!
println("should have run program now")

execute

[ -f /tmp/ammonite-2.13/amm ] || (mkdir /tmp/ammonite-2.13 -p && curl -L https://github.com/lihaoyi/Ammonite/releases/download/2.1.4/2.13-2.1.4 > /tmp/ammonite-2.13/amm && chmod +x /tmp/ammonite-2.13/amm) && /tmp/ammonite-2.13/amm script.sc

expected behavior

program runs the effect

actual behavior

program runs till the unsafeRun, then just hangs without executing the effect

aditional info

⇒  jstack 59938
2021-03-15 22:08:50
Full thread dump OpenJDK 64-Bit Server VM (11.0.10+8-jvmci-21.0-b06 mixed mode, sharing):

Threads class SMR info:
_java_thread_list=0x00007fec58f313c0, length=26, elements={
0x00007fec5a009000, 0x00007fec39808800, 0x00007fec59824000, 0x00007fec59834800,
0x00007fec5a80d800, 0x00007fec5a810800, 0x00007fec5a813000, 0x00007fec5a81c000,
0x00007fec3a014000, 0x00007fec5aadc800, 0x00007fec3b50c800, 0x00007fec3b519000,
0x00007fec39a10800, 0x00007fec3b544000, 0x00007fec39a11800, 0x00007febf900f000,
0x00007fec3a525800, 0x00007febf9014000, 0x00007fec5ae23800, 0x00007fec5a48f800,
0x00007fec5a492800, 0x00007febf9023000, 0x00007fec59c91000, 0x00007fec5ae1c800,
0x00007febf9023800, 0x00007fec5a85c000
}

"main" #1 prio=5 os_prio=31 cpu=3335.43ms elapsed=41.35s tid=0x00007fec5a009000 nid=0x2703 in Object.wait()  [0x00007000100d0000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(java.base@11.0.10/Native Method)
    - waiting on <0x00000007f9407938> (a zio.internal.OneShot)
    at java.lang.Object.wait(java.base@11.0.10/Object.java:328)
    at zio.internal.OneShot.get(OneShot.scala:79)
    - waiting to re-lock in wait() <0x00000007f9407938> (a zio.internal.OneShot)
    at zio.Runtime.unsafeRunSync(Runtime.scala:83)
    at zio.Runtime.unsafeRunSync$(Runtime.scala:78)
    at zio.Runtime$$anon$3.unsafeRunSync(Runtime.scala:273)
    at zio.Runtime.unsafeRun(Runtime.scala:58)
    at zio.Runtime.unsafeRun$(Runtime.scala:57)
    at zio.Runtime$$anon$3.unsafeRun(Runtime.scala:273)
    at ammonite.$file.simpletest$.<clinit>(simpletest.sc:11)
    at ammonite.$file.simpletest.$main(simpletest.sc)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.10/Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.10/NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.10/DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(java.base@11.0.10/Method.java:566)
    at ammonite.runtime.Evaluator$$anon$1.$anonfun$evalMain$1(Evaluator.scala:108)
    at ammonite.runtime.Evaluator$$anon$1$$Lambda$1244/0x000000084074e440.apply(Unknown Source)
    at ammonite.util.Util$.withContextClassloader(Util.scala:24)
    at ammonite.runtime.Evaluator$$anon$1.evalMain(Evaluator.scala:90)
    at ammonite.runtime.Evaluator$$anon$1.$anonfun$processScriptBlock$1(Evaluator.scala:153)
    at ammonite.runtime.Evaluator$$anon$1$$Lambda$1243/0x000000084074e840.apply(Unknown Source)
    at ammonite.util.Catching.map(Res.scala:117)
    at ammonite.runtime.Evaluator$$anon$1.processScriptBlock(Evaluator.scala:150)
    at ammonite.interp.Interpreter.$anonfun$processSingleBlock$4(Interpreter.scala:329)
    at ammonite.interp.Interpreter$$Lambda$1241/0x000000084074d840.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.$anonfun$processSingleBlock$3(Interpreter.scala:320)
    at ammonite.interp.Interpreter$$Lambda$1235/0x0000000840749040.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.$anonfun$processSingleBlock$2(Interpreter.scala:317)
    at ammonite.interp.Interpreter$$Lambda$689/0x000000084054c840.apply(Unknown Source)
    at ammonite.util.Catching.flatMap(Res.scala:115)
    at ammonite.interp.Interpreter.processSingleBlock(Interpreter.scala:316)
    - locked <0x00000007e22224e8> (a ammonite.interp.Interpreter)
    at ammonite.interp.Interpreter.$anonfun$processModule$8(Interpreter.scala:397)
    at ammonite.interp.Interpreter$$Lambda$303/0x0000000840267040.apply(Unknown Source)
    at ammonite.interp.Interpreter.$anonfun$processAllScriptBlocks$3(Interpreter.scala:525)
    at ammonite.interp.Interpreter$$Lambda$684/0x0000000840549840.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.compileRunBlock$1(Interpreter.scala:511)
    at ammonite.interp.Interpreter.$anonfun$processAllScriptBlocks$15(Interpreter.scala:572)
    at ammonite.interp.Interpreter$$Lambda$378/0x00000008402b4040.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.$anonfun$processAllScriptBlocks$14(Interpreter.scala:569)
    at ammonite.interp.Interpreter$$Lambda$324/0x0000000840275040.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.$anonfun$processAllScriptBlocks$12(Interpreter.scala:566)
    at ammonite.interp.Interpreter$$Lambda$309/0x000000084026b040.apply(Unknown Source)
    at scala.Option.getOrElse(Option.scala:201)
    at ammonite.interp.Interpreter.loop$1(Interpreter.scala:566)
    at ammonite.interp.Interpreter.processAllScriptBlocks(Interpreter.scala:604)
    - locked <0x00000007e22224e8> (a ammonite.interp.Interpreter)
    at ammonite.interp.Interpreter.$anonfun$processModule$6(Interpreter.scala:399)
    at ammonite.interp.Interpreter$$Lambda$301/0x0000000840265040.apply(Unknown Source)
    at ammonite.util.Catching.flatMap(Res.scala:115)
    at ammonite.interp.Interpreter.$anonfun$processModule$5(Interpreter.scala:390)
    at ammonite.interp.Interpreter$$Lambda$300/0x0000000840263840.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.interp.Interpreter.processModule(Interpreter.scala:380)
    - locked <0x00000007e22224e8> (a ammonite.interp.Interpreter)
    at ammonite.main.Scripts$.$anonfun$runScript$1(Scripts.scala:26)
    at ammonite.main.Scripts$$$Lambda$175/0x0000000840215040.apply(Unknown Source)
    at ammonite.util.Res$Success.flatMap(Res.scala:62)
    at ammonite.main.Scripts$.runScript(Scripts.scala:22)
    at ammonite.Main.runScript(Main.scala:239)
    at ammonite.MainRunner.$anonfun$runScript$1(Main.scala:410)
    at ammonite.MainRunner$$Lambda$105/0x000000084017f040.apply(Unknown Source)
    at ammonite.MainRunner.watchLoop(Main.scala:396)
    at ammonite.MainRunner.runScript(Main.scala:410)
    at ammonite.Main$.main0(Main.scala:334)
    at ammonite.Main$.main(Main.scala:270)
    at ammonite.Main.main(Main.scala)
adamgfraser commented 3 years ago

Any Ammonite users who can comment on this? I have a hard time believing ZIO just doesn't work on Ammonite, in fact I know it does because we have special support for it in ZIO Test, but doesn't use it personally.

domdorn commented 3 years ago

I just got feedback in the ammonite-gitter. When putting the unsafeRun call into a main method, it starts to work

val program = ....

@main
def main( path: os.Path = os.pwd) = {
        println("should run program now")
        println(program)
        println()
        zio.Runtime.default.unsafeRun(program.provideLayer(zio.ZEnv.live)) // here it just blocks and does nothing!
        println("should have run program now")
}

maybe we can put this into the docs somewhere?

jdegoes commented 3 years ago

It would be good to coordinate with Li to see if there is some way we can work around behavior. Technically this isn't a bug in ZIO, but Ammonite is a very important tool to work smoothly with.

domdorn commented 3 years ago

so, I have a new insight: it looks like everything that is trying to spawn a thread outside the scope of a @main def xxx() method is blocking the whole thing, e.g. even using the parallel collections of scala. I guess it might have something todo with that the code outside a @main annotated method would be basically the static initializer of a class? not sure, but this is what I observed

adamgfraser commented 3 years ago

Yes it seems like this really needs to be handled on the Ammonite end.

ajrnz commented 2 years ago

I'm pretty sure the is related to https://github.com/com-lihaoyi/Ammonite/issues/534 which is closed by shouldn't be. I've run into it a lot. eg this fails

    val f = Future {
      println("a")
    }

    Await.result(f, 1 second)

but if you wrap it in an object or main function it is ok.

So:

  @main
  def main() = {
    ...
  }
domdorn commented 2 years ago

After thinking about it, running an effect outside the @main basically is the same as in this screenshot image

Maybe we can find a way to make a suitable error message or something