Доброе утро! Сначала немного личных новостей: я перехожу на NixOS, и я в некотором роде взволнован этим, так что ожидайте несколько статей по этому поводу. Сегодня я отмечаю легкость, с которой я получил среду Play Framework, включая установку sbt и понижение версии до JDK 11.
Как разработчик программного обеспечения, я не очень ценю необходимость бороться со своим окружением, поэтому, когда я услышал, что NixOS использует чисто функциональный, декларативный подход к сопровождению пакетов, я заинтересовался. В последнее время мой подход к поддержанию чистого рабочего стола вращался вокруг docker, так что я открыт для менее хакерских подходов.
Настоящим испытанием стал sbt, который, по моему опыту, является привередливой частью программного обеспечения. Все, что зависит от Java, и так может стать сложным, а sbt особенно привязан к состоянию, поскольку он загружает свои зависимости на лету. До сих пор мне не удалось заставить работать трюк с Docker и псевдонимами, описанный выше.
Установка sbt
на NixOS
…приятно тривиальна. В официальном репозитории есть пакет sbt
, который можно установить обычным для NixOS способом в списке пакетов в файле /etc/nixos/configuration.nix.
/etc/nixos/configuration.nix
...
environment.systemPackages = with pkgs; [
docker
emacs
firefox
git
gnome.gnome-tweaks
sbt
wget
];
...
Затем, чтобы изменения вступили в силу, выполните sudo nixos-rebuild switch
.
После этого я могу запустить sbt
в существующем проекте, и он работает без проблем.
Но он не совместим с Play во время выполнения.
UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
Когда я запускаю приложение, оно обслуживает исключения:
вывод консоли
--- (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)
...
трассировка стека со страницы ошибок
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)
Обе приведенные трассировки стека продолжаются целую вечность, проходя через различные библиотеки Play, Akka, Google и даже основную библиотеку Java, находясь далеко внизу стека от реального кода приложения.
Совместимость с Play Framework
Быстрый поиск подсказал мне, что другие люди сталкиваются с этой проблемой при запуске Play Framework на несовместимых версиях Java, и что Play Framework 2.8 (текущая версия на момент написания статьи) совместим с JDK 8 и JDK 11. Конечно, когда я наблюдал за запуском sbt
, я увидел, что он использует JDK 17, поэтому я понял, что мне нужно понизить версию до JDK 11.
Я попытался установить пакет JDK 11, используя тот же /etc/configuration.nix, но, конечно, особенность Nix в том, что это не так — каждый пакет поставляется со своими зависимостями, а sbt по-прежнему использует JDK 17.
Поэтому вопрос в том, как мне понизить версию JDK, которую использует sbt, с JDK 11 до JDK.
И это заставляет меня немного чесаться. Будет ли это сложно? Придется ли мне форкнуть пакет sbt? Потому что причина, по которой я перешел на NixOS в первую очередь, заключается в том, чтобы избежать таких сложностей.
Понижение версии JDK, используемой sbt
Оказывается, это просто. Версия Java, используемая пакетом sbt, может быть декларативно переопределена в той же строке конфигурационного файла.
/etc/nixos/configuration.nix
...
environment.systemPackages = with pkgs; [
docker
emacs
firefox
git
gnome.gnome-tweaks
(sbt.override { jre = pkgs.jdk11; })
wget
];
...
Затем просто nixos-rebuild switch
и все готово!
В заключение… Я думаю, мне это нравится!
С одной стороны, я был пользователем Ubuntu почти десять лет. Я знаю, как быть продуктивным в ней. Когда что-то ломается, я обычно могу это исправить, а если не могу, то могу понять, с каких поисковых запросов лучше начать. С другой стороны, мне кажется, что я только сейчас начинаю понимать, насколько мощным на самом деле является nix
. Если я смогу создать идеально воспроизводимое окружение Scala с помощью одной строки, то уже одно это может стоить того, чтобы остаться здесь. Уверен, дальше будет больше.