Запуск Play Framework на NixOS с использованием JDK 11

Доброе утро! Сначала немного личных новостей: я перехожу на 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 с помощью одной строки, то уже одно это может стоить того, чтобы остаться здесь. Уверен, дальше будет больше.

Оцените статью
devanswers.ru
Добавить комментарий