Running Play Framework on NixOS using JDK 11
webbureaucrat
Posted on August 8, 2022
Good morning! First, some personal news: I'm switching to NixOS, and I'm kind of excited about it, so expect some articles to that effect. Today, I'm celebrating the ease with which I got a Play Framework environment up and running, including installing sbt and downgrading to JDK 11.
As a software developer, I do not at appreciate having to fight with my environment, so when I heard that NixOS uses a purely functional, declarative approach to maintaining packages, I was interested. Recently, my approach maintaining a clean desktop has revolved around docker, so I'm open to less hacky approaches for sure.
The real test is sbt, which in my experience is a finicky piece of software. Anything with a Java dependency can get complicated already, and sbt is particularly stateful as it downloads its dependencies on the fly. So far I haven't been successful getting the Docker-and-alias trick above to work.
Installing sbt
on NixOS
...is pleasantly trivial. There is an sbt
package in the official repository which can be installed in the usual NixOS way in the packages list in the /etc/nixos/configuration.nix file.
/etc/nixos/configuration.nix
...
environment.systemPackages = with pkgs; [
docker
emacs
firefox
git
gnome.gnome-tweaks
sbt
wget
];
...
Then, to make the change take effect, run sudo nixos-rebuild switch
.
After this, I can run sbt
against my existing project and it works smoothly.
But it's not compatible with Play at runtime.
UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
When I run the application, it serves exceptions:
console output
--- (Running the application, auto-reloading is enabled) ---
p.c.s.AkkaHttpServer - Listening for HTTP on /[0:0:0:0:0:0:0:0]:9000
(Server started, use Enter to stop and go back to the console...)
2022-07-04 12:46:00 ERROR p.api.http.DefaultHttpErrorHandler
! @7o7k89hhe - Internal server error, for (GET) [/] ->
play.api.UnexpectedException: Unexpected exception[UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item]
at play.core.server.DevServerStart$$anon$1.reload(DevServerStart.scala:254)
at play.core.server.DevServerStart$$anon$1.get(DevServerStart.scala:148)
at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:302)
at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$1(AkkaHttpServer.scala:224)
at akka.stream.impl.fusing.MapAsync$$anon$30.onPush(Ops.scala:1307)
at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:542)
...
stack trace from error page
com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2051)
com.google.common.cache.LocalCache.get(LocalCache.java:3962)
com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3985)
com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4946)
com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4952)
com.google.inject.internal.FailableCache.get(FailableCache.java:54)
com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore.java:49)
com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:155)
com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:592)
Both stack traces given go on for ages winding through various Play, Akka, Google, and even core Java libraries, far downstack from the actual application code.
Play Framework Compatibility
A quick search tells me that other people have this problem when running Play Framework against incompatible Java versions and that Play Framework 2.8 (the current version at the time of this writing) is compatible with JDK 8 and JDK 11. Sure enough, when I watched sbt
startup, I saw that it used JDK 17, so I knew I needed to downgrade to JDK 11.
I tried installing the JDK 11 package using the same /etc/configuration.nix, but of course it's a feature of Nix that that's not how that works--each package comes with it's own dependencies, and sbt uses JDK 17 still.
So the question is: How do I downgrade the JDK version that sbt uses from JDK 11 to JDK.
And this makes me a little itchy. Is this going to be hard? Am I going to have to fork the sbt package? Because the reason why I switched to NixOS in the first place is to avoid going to such lengths.
Downgrading the JDK version used by sbt
It turns out it's easy. The Java version used by the sbt package can be overridden declaratively within that same line in the configuration file.
/etc/nixos/configuration.nix
...
environment.systemPackages = with pkgs; [
docker
emacs
firefox
git
gnome.gnome-tweaks
(sbt.override { jre = pkgs.jdk11; })
wget
];
...
Then just nixos-rebuild switch
and you're good to go!
In Conclusion... I think I like this!
On the one hand, I've been an Ubuntu user for almost ten years. I know how to be productive there. When things break, I can generally fix them, and if I can't, I can generally figure out what would be good search terms to start with. On the other hand, I think I'm just getting a glimpse of just how powerful nix
really is. If I can make a perfectly reproducible Scala environment with a single line, that alone might be worth sticking around for. More to come, I'm sure.
Posted on August 8, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.