-
-
Notifications
You must be signed in to change notification settings - Fork 180
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Boot lein uberjar equivalent - performance challenges #94
Comments
I wonder if leiningen is using previously compiled files if they exist. Could you test leiningen again after running |
Timed both several times with rm -rf target as precondition. Should have mentioned. |
Hi, thank you for the great analysis, and for the kind words! For debugging your Re: your build.boot, this is a minor enhancement but you can actually add repositories by putting a function as the value for any key including
OK now for the less-than-good news. Boot represents filesystems using an immutable data structure we call the Fileset. Fileset values are what handlers are passed, and also what they pass to the next handler. At the end of the build we emit the fileset value we got from the last handler into the target directory. Filesets are maybe the most important abstraction in boot, because they prevent tasks from having to coordinate around places on disk, which is effectively a shared/global namespace. Instead, because filesets are values, tasks can compose using normal functional/programming means, and tasks don't need to know or care about the shape of the "real" filesystem at all. Right, getting to the bad news. So nothing we've seen so far taxes the fileset idea quite like the uberjar. The fileset was originally conceived to work with sources -- code being actively edited by the user of boot in a development session -- not exploded dependencies that don't change between build invocations. Unfortunately, even the smallest uberjar projects can have tens of thousands of files in the fileset depending on their dependencies. There are definitely avenues for improving Fileset performance left to explore, and after exploring them we might be nearly as fast as lein. It's possible (but would suck) that uberjar is a special thing, and we need to special-case it somehow. We'll be looking into it, but help improving uberjar before 2.0.0 would be graciously accepted. In the meantime there are some workarounds I do personally and can imagine. At work we bypass uberjar completely by making boot the entrypoint for our webapps. We deploy our apps to AWS ElasticBeanstalk using a Dockerfile like this one and this boot task. This pawns the work of downloading the dependencies off on the app container, and makes for faster deployments because we only have to upload the repo source, not all dependencies. Tasks configure themselves in the container based on environment variables. That Dockerfile is actually used to launch 2 different SQS workers and a daemon, each with a different startup function. Which function to run is determined by the Another workaround I can imagine is a task that emits a |
Are you passing the same JVM OPTS to boot that you pass to leiningen? (Might be still slow) |
@martinklepsch I haven't set any specific jvm options for lein. I tried tinkering with BOOT_JVM_OPTIONS as per your wiki, but with minimal impact (perhaps slightly faster startup, but thats just drops in the sea compared to the elapsed time for compiling, uber and jaring. @alandipert Thx for your elaborate answer. I'd love to contribute, but I'm just a few months into working with clojure in anger. It'll take some time before I'll be able to contribute anything really meaningful I suppose. I've previously worked on porting large builds from maven to gradle. I see some parallels to maven->gradle with lein->boot. I see a lot of promise in boot so far. A bit like when I first discovered gradle after tearning my hair out trying to tweak maven to do something beyond what maven thinks a build default should do. I think there are some good ideas/inspirational areas to be cherry-picked from gradle (like incremental tasks, parallell task execution, the gradle wrapper etc). I'm digressing. I'm not in a hurry, I'll keep running lein for a while longer but will try to keep a parallel boot build functional. For boot the tool to get higher adoption in particular for clojure ring projects, I guess some dramatic performance enhancements needs to be implemented though. If I am able to contribute (either with code or testing if that helps) I'm happy to do so. |
@rundis it would be great to have a reference project to measure progress with this. I've been working on uberjar performance a lot lately, things are getting much better. |
I think the worst of the uber task performance issues have been resolved. |
Is the performance issue really resolved? What commit resolved it? |
I created a boot port of my lein build.
It worked (after I build boot from source and ran lein install).
In summary:
On my mac (mavericks) with jdk1.8.0_25:
build.boot
Running a leiningen build yields:
Running with boot yields:
A couple of other thoughts:
Anyways, Boot looks really exciting ! Keep up the good work :)
The text was updated successfully, but these errors were encountered: