zio-http icon indicating copy to clipboard operation
zio-http copied to clipboard

Support Graal Native Image

Open tusharmath opened this issue 3 years ago • 16 comments

The resulting program has faster startup time and lower runtime memory overhead compared to a JVM

https://www.graalvm.org/reference-manual/native-image

  • [ ] Add documentation about how to get started with GraalVM and ZIO Http
  • [ ] Add a CI check to ensure all builds compile on GraalVM.

tusharmath avatar Mar 12 '21 17:03 tusharmath

Here is a sample that has the required config: https://github.com/jamesward/hello-zio-http/tree/graalvm

jamesward avatar Mar 15 '21 19:03 jamesward

Unfortunately, that config isn't working for me in my project. Perhaps things changed with the versions. Or perhaps I'm doing it wrong. :'(

I can't seem to avoid:

 io.netty.util.AbstractReferenceCounted the class was requested to be initialized at run time (from the command line). io.netty.util.AbstractReferenceCounted has been initialized without the native-image initialization instrumentation and the stack trace can't be tracked. Try avoiding to initialize the class that caused initialization of io.netty.util.AbstractReferenceCounted
io.netty.channel.DefaultFileRegion the class was requested to be initialized at run time (subtype of io.netty.util.AbstractReferenceCounted). io.netty.channel.DefaultFileRegion has been initialized without the native-image initialization instrumentation and the stack trace can't be tracked. Try avoiding to initialize the class that caused initialization of io.netty.channel.DefaultFileRegion

kitlangton avatar May 25 '21 03:05 kitlangton

I bumped stuff up to the latest: https://github.com/jamesward/hello-zio-http/commit/4d291523dce52c08a98471adc358215070a25b23

Note the GraalVM configs in the build.sbt which are for Netty: https://github.com/jamesward/hello-zio-http/blob/graalvm/build.sbt#L97-L108

Hopefully that helps.

jamesward avatar May 25 '21 11:05 jamesward

For Linux, the config @jamesward posted worked as is for me. When I tried to build a native image for macOS (without Docker or anything like that), I got the same errors @kitlangton was seeing.

I was able to get it working by adding the following to the config that's already there:

"--initialize-at-run-time=io.netty.util.AbstractReferenceCounted",
"--initialize-at-run-time=io.netty.channel.kqueue.KQueue",

and then you also have to remove --static on macOS, otherwise you'll get:

com.oracle.svm.core.util.UserError$UserException: DARWIN does not support building static executable images.

After that it worked. Startup is instantaneous 🙂

reibitto avatar May 25 '21 14:05 reibitto

Nice @reibitto!

jamesward avatar May 25 '21 14:05 jamesward

Oh wow, I also tested this on native Windows and it worked! Setting up the Windows environment for Graal native-image is a little tricky (refer to this), but I didn't have to make any changes to the hello-zio-http project itself. I was not expecting that 😅

Unsurprisingly it also works with WSL.

reibitto avatar May 25 '21 15:05 reibitto

<3 <3 <3 Thank you all so much. I lost an embarrassing number of hours to this yesterday. Excited to try this out :)

kitlangton avatar May 25 '21 15:05 kitlangton

@kitlangton You've made it through the Native Image initiation rites! You should see my scars.

jamesward avatar May 25 '21 16:05 jamesward

🤖 Native... Image... Ready

😭

kitlangton avatar May 25 '21 16:05 kitlangton

Never has it felt so good to be startled by those words.

kitlangton avatar May 25 '21 16:05 kitlangton

Oh, that makes sense. You were using sbt-native-image, not sbt-native-packager, right? sbt-native-image doesn't support Docker.

reibitto avatar May 25 '21 16:05 reibitto

Oh, that makes sense. You were using sbt-native-image, not sbt-native-packager, right? sbt-native-image doesn't support Docker.

Yeah! Your guess was correct (in the zio-http discord) that I'm using it as a local dev server for this https://twitter.com/kitlangton/status/1396918103414427648. Main goal is instant start-up.

kitlangton avatar May 25 '21 16:05 kitlangton

Can anyone make native-image compile then run successfully when including quill-jdbc-zio? After I added quill-jdbc-zio (I was able to isolate the problem to just this lib in my project), I had to add a lot of more --initialize-at-run-time entries. Then even when it succeeded building the image, my app crashed upon launch with this error message:

java.lang.NoClassDefFoundError: Could not initialize class io.netty.buffer.ByteBufAllocator

@jamesward @reibitto If you can look into this, I'd greatly appropriated. I just wish GraalVM's dev experience is much better than trial'n'errors. I apologize for asking here @tusharmath... it's not often to get James and Reibitto in the same thread, and I know both have good experience with Graal. Thanks in advance.

ithinkicancode avatar Jul 08 '21 21:07 ithinkicancode

@ithinkicancode That's weird because I don't think quill even uses netty. If it's complaining about netty, then the problem might be coming from zio-http. But you're saying it only happens when you add quill-jdbc-zio to the project?

I'm actually going to try using native-image in one of my projects which happens to also use quill, so I might learn something in that process. If I manage to do it successfully I can let you know. If I forget, then it's this project. I need a little time though because I have to finish swapping out akka-http for zio-http first.

reibitto avatar Jul 11 '21 16:07 reibitto

At least one of the async drivers uses netty: https://github.com/postgresql-async/postgresql-async

joprice avatar Jul 11 '21 18:07 joprice

As a followup to this issue, according to https://github.com/lampepfl/dotty/issues/13985, the main LazyVal problem is fixed but its still not released (apparently will be on Scala 3.3) and then it will require that all libs are built with this new compiler.

Another option is using scala-cli package command which does the bytecode manipulation as mentioned in the issue (https://github.com/lampepfl/dotty/issues/13985#issuecomment-1318525950) automatically.

I found a couple more flags required to be initialized and added it to a sample repo at https://github.com/carlosedp/ziohttp. It has a script to package the application to a native-image.

For the curious, the bytecode manip code is at https://github.com/VirtusLab/scala-cli/tree/main/modules/scala3-graal/src/main/scala/scala/cli/graal

carlosedp avatar Dec 05 '22 23:12 carlosedp