Modernize the toolchain: Scala 2.13.16, JDK 21, Apache Pekko, and wider PostgreSQL support#1383
Draft
GeekOfWires wants to merge 7 commits into
Draft
Modernize the toolchain: Scala 2.13.16, JDK 21, Apache Pekko, and wider PostgreSQL support#1383GeekOfWires wants to merge 7 commits into
GeekOfWires wants to merge 7 commits into
Conversation
Toolchain: - Scala 2.13.10 -> 2.13.16 - sbt 1.8.2 -> 1.10.7 (needed for JDK 21 in a later phase) Libraries (patch/minor only, no slf4j-2 / cross-major boundary crossings): - specs2 4.20.9, scalatest 3.2.19, logback 1.2.13, jansi 2.4.1, nscala-time 2.34.0, json4s 4.0.7, config 1.4.3, pureconfig 0.17.7, enumeratum 1.7.3, commons-io 2.16.1, sentry 6.34.0, circe 0.14.9 Scala 2.13.16 source/tooling fixes (so the bump actually builds): - Zones.scala: annotate the anonymous-subclass `val zone` with an explicit `: Zone` type; 2.13.16 rejects the recursive value (its body references it). - semanticdb disabled: sbt-scalafix 0.10.4 pins semanticdb 4.6.0, which has no 2.13.16 build; re-enable with a scalafix bump that supplies a compatible semanticdb (linter only; does not affect compilation or tests). - sbt plugins left at their existing versions (earlier speculative bumps did not resolve; plugin currency is out of scope for this branch). Deferred to later phases: Akka->Pekko, postgres/flyway/quill, bcprov jdk15on->jdk18on, and the coupled scodec-2 / scala-graph-2 / logback-1.5 bumps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Pekko is the Apache-2.0 licensed fork of Akka 2.6.x; a drop-in namespace/
coordinate migration across ALL source roots (src/, server/, tools/).
- build.sbt: com.typesafe.akka:*:2.6.20 -> org.apache.pekko:*:1.1.3
(pekko-http 10.2.10 -> 1.1.0); removed the "do not upgrade (BSL)" pin.
- Source: akka.* -> org.apache.pekko.* across root src/, the server/ subproject,
and tools/ (actor/util/pattern/io/event/dispatch/stream/testkit + all imports),
including Server.scala's aliased `import akka.{actor => classic}`.
- Two files in the actor package to reach internals moved akka.actor ->
org.apache.pekko.actor: MDCContextAware (protected[akka] aroundReceive ->
protected[pekko]) and MDCPropagatingExecutionContext.
- Vendored scodec<->ByteString interop renamed scodec.interop.akka ->
scodec.interop.pekko (Scala package object + the Java PrivacyHelper reaching
Pekko's bytecode-public ByteString1C) and its 3 importers.
- Config: akka.conf -> pekko.conf; namespace akka{} -> pekko{}, logger class
values -> org.apache.pekko.*; application.conf include; test config paths
akka.* -> pekko.* (root + server ActorTest).
- Two server tests (AutoRepair{,Integration}Test): the cross-package relative
`import base.FreedContextActorTest` absolutized to
`import actor.base.FreedContextActorTest` (Scala 2.13.16 no longer resolves
the relative-sibling form).
Verified: all source roots compile (root + server + tools) on Pekko 1.1.3.
Follow-ups (not blocking): unused pekko-stream/http/cluster-*/protobuf-v3 kept
for parity; Kamon still carries Akka instrumentation (add kamon-pekko later,
kanela no-ops on absent classes).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Dockerfile builder: JDK 11 image -> sbtscala JDK 21 image (exact tag flagged in a comment to confirm on Docker Hub; the project's Scala/sbt come from build.sbt/build.properties, not the image). - Dockerfile runtime: openjdk:18-slim -> eclipse-temurin:21-jre (openjdk images are deprecated; this also aligns build and runtime on one JDK, fixing the prior 11/18 split). - CI (test.yaml): coursier jvm adopt:11 -> temurin:21. - bcprov-jdk15on 1.70 -> bcprov-jdk18on 1.78.1 (jdk15on is the legacy artifact name; jdk18on is the modern-JDK build; API-compatible). JDK 21 is supported now that the actor toolkit is Pekko 1.1 (JDK 8/11/17/21); Akka 2.6 was only supported through JDK 17. Not built in-session (no Docker/sbt); confirm the builder image tag, then build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Driver/migration stack (enabled by the JDK 21 move):
- postgresql JDBC 42.5.4 -> 42.7.4 (spans PG12..18; still supports the current
12.8 CI / 14 compose servers).
- Flyway 9.16.0 -> 10.20.1 + the now-separate flyway-database-postgresql module
(Flyway 10 is modular). 10.x supports PG16/17 and requires JDK 17+, which Phase 2
provides. Server.scala already uses the 10-compatible configure()/load() API.
- Config.toJdbc now passes the configured sslmode to the Flyway/JDBC connection so
it matches the jasync runtime path (they previously negotiated TLS differently).
Prove-and-preserve, not a version swap:
- docker-compose postgres image parameterized: postgres:${POSTGRES_VERSION:-14}.
- CI runs a PostgreSQL matrix [12.8, 16, 17] (fail-fast off) so migrations + tests
are proven on newer majors while the current 12.8 stays green.
Deliberately NOT changed:
- Existing V001..V017 migrations are untouched -- editing an applied migration breaks
Flyway checksum validation. The legacy `EXECUTE PROCEDURE` trigger syntax still works
through PG17; modernizing to `EXECUTE FUNCTION` needs a new migration (follow-up).
- Runtime driver quill-jasync 3.18.0 / jasync 1.2.3 kept as-is; the CI matrix will
surface whether a jasync 2.x + matching Quill bump is actually needed for newer PG,
rather than bumping the fragile pairing blind.
Not built in-session (sbt unavailable); run the matrix to validate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LocalActionTest references Default.GUID0 but never imported net.psforever.objects.Default (unlike its sibling tests). This is a pre-existing gap in the base psforever#1379 commit, surfaced when the test sources were compiled during the modernization verification -- not a modernization change. Adds the import so the test suite compiles. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
….5.18 The JDK 21 move (Phase 2) was verified for compile and test but not for `server/run`, which attaches the Kanela instrumentation agent. On JDK 21 the old agent aborted startup: Unable to start Kanela Agent ... Failed to resolve the class file version of the current VM: Unknown Java version: 0 kamon-bundle 2.6.1 / sbt-kanela-runner 2.0.14 ship Kanela 1.0.11, whose ByteBuddy predates JDK 21. Bumping to kamon-bundle/apm-reporter 2.7.7 and sbt-kanela-runner 2.1.1 pulls Kanela 1.0.18 (JDK 21-aware) with a matching instrumentation API. kamon 2.7.7's dependency tree then resolves slf4j-api 2.0.x, which ignores logback-classic 1.2.13's 1.7-era binding (NOPLoggerFactory -> ClassCastException at Server.scala when casting to logback's LoggerContext). Bumping logback-classic to 1.5.18 provides the slf4j 2.0 service provider. Verified: full test suite unchanged (192 pass / 38 fail scalatest + 3 specs2 -- the pre-existing psforever#1379 baseline, no new regressions) and the server boots on JDK 21 (Pekko Slf4jLogger started, Kamon module registry active). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The JDK 21 sbt builder tag used by the Dockerfile and docker-compose (eclipse-temurin-jammy-21.0.5_11_1.10.7_2.13.16) is not published on Docker Hub, so image pulls failed. No sbtscala/scala-sbt tag bundles sbt 1.10.7 + Scala 2.13.16; the launcher fetches those from build.properties/build.sbt regardless, so the image only needs to provide JDK 21 + an sbt launcher. Switch both to the newest available JDK 21 tag (21.0.2_13_1.10.4_2.13.15). Also update docker-compose: - loginserver was still on the pre-modernization JDK 8 / Scala 2.13.10 image, which cannot build the Pekko/JDK 21 code; move it to the JDK 21 image. - default the db service to postgres:18 (newest major) via POSTGRES_VERSION. Verified end to end: the full stack boots, the server auto-migrates a fresh PostgreSQL 18.4 database (Flyway applies all 17 migrations; Flyway 10.20.1 emits only a soft "newer than tested" warning), and the login server listens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Process Proposal
This PR exists primarily to give the project visibility into the full process of making
the changeover, shown as one continuous path rather than a polished end state. It is
admittedly larger than a comfortable single merge, and would reasonably be broken up
before landing.
It is presented here as a single pull request because the changes are interdependent:
getting from Akka-runnable on the earlier JDK to Pekko-runnable on the latest JDK took
several linked steps — toolchain bump → Akka→Pekko migration → JDK 21 → the runtime and
dependency fixes that only surface once the server actually boots — and no single step is
runnable on its own without the others. Keeping them together documents the real path taken
and lets reviewers see exactly what each hop required, before deciding how to slice it for
merge.
Summary
This branch modernizes the build/runtime stack in small, individually-reviewable phases,
each in its own commit. Nothing in game logic or the network protocol changes — this is
purely infrastructure. It compiles green, runs on JDK 21, and introduces zero test
regressions (evidence below).
Phase 0: bump Scala, sbt, and low-risk dependenciesPhase 1: migrate Akka 2.6.20 -> Apache Pekko 1.1.xakka.*→org.apache.pekko.*(pekko-actor 1.1.3, pekko-http 1.1.0),akka.conf→pekko.conf, config namespaceakka { }→pekko { }Phase 2: move build/runtime/CI to JDK 21eclipse-temurin:21-jreruntime, CI JVM → temurin 21, bcprov-jdk18on 1.78.1Phase 3: widen PostgreSQL version supportAdd missing Default import in LocalActionTestmaster(see below)Enable server runtime on JDK 21: Kamon 2.7.7, Kanela 2.1.1, logback 1.5.18Fix Docker image tag; run compose stack on JDK 21 / Postgres 18Why
2.7.0; the project is pinned to the last Apache-2.0 Akka (2.6.20). Apache Pekko 1.x is the
community fork of Akka 2.6.x under Apache-2.0 and is a near drop-in (namespace change only).
Migrating now keeps the actor layer on a permissively-licensed, actively-maintained base and
unblocks future actor/stream/HTTP upgrades.
actively supported; the previous sbt 1.8.2 / Scala 2.13.10 combination will not even start
on JDK 21.
PostgreSQL majors (verified up to 18) while the CI matrix keeps proving the current 12.8
still migrates — no forced deprecation.
Verification
sbt clean testcompiles all source roots and runs the full suite on JDK 21.Slf4jLoggerstarts, Flyway applies all 17 migrations to a fresh PostgreSQL 18.4database, and the login server listens. (Flyway 10.20.1 emits only a soft "newer than
tested" warning on PG 18 and migrates successfully.)
Test status — please read
The suite currently reports 192 pass / 38 fail (scalatest) + 3 specs2 failures. These are
not introduced by this branch — they reproduce identically on today's
master. I confirmedthis with a full attribution matrix:
master(unchanged)Same count, same suites across every axis → the Pekko/JDK/Scala changes flip none of them.
The failing suites are timing-sensitive
objects.*ActorTests (theActorTestbase classdocuments this flakiness) tied to the message bundling introduced in #1379; a same-toolchain
Akka baseline reproduces them identically. Happy to share the full per-suite breakdown.
Separately, the
Add missing Default import in LocalActionTestcommit fixes a spot wheremaster's test sources don't currently compile (LocalActionTestreferencesDefault.GUID0without importing
net.psforever.objects.Default).Deliberately conservative / follow-ups
pekko-stream/pekko-http/ cluster modules are kept for parity but have no directimports yet — safe removal candidates in a follow-up.
sbt-scalafixis temporarily disabled (semanticdbEnabled := false) because 0.10.4 pins asemanticdb with no 2.13.16 build; re-enable alongside a scalafix bump.
kamon-pekkoinstrumentation and a jasync/Quill bump are left for a later pass.Reviewing commit-by-commit is recommended — each phase stands on its own and can be split into
separate PRs if that's preferred.
Prepared with assistance from Claude (Opus 4.8); commits carry
Co-Authored-Bytrailers accordingly.