zio-http
zio-http copied to clipboard
Support Graal Native Image
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.
Here is a sample that has the required config: https://github.com/jamesward/hello-zio-http/tree/graalvm
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
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.
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 🙂
Nice @reibitto!
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.
<3 <3 <3 Thank you all so much. I lost an embarrassing number of hours to this yesterday. Excited to try this out :)
@kitlangton You've made it through the Native Image initiation rites! You should see my scars.
🤖 Native... Image... Ready
😭
Never has it felt so good to be startled by those words.
Oh, that makes sense. You were using sbt-native-image
, not sbt-native-packager
, right? sbt-native-image
doesn't support Docker.
Oh, that makes sense. You were using
sbt-native-image
, notsbt-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.
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 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.
At least one of the async drivers uses netty: https://github.com/postgresql-async/postgresql-async
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