Skip to content

fix(jdbc): unique HikariCP pool name per SlickDatabase provider (#13)#14

Merged
fupelaqu merged 1 commit into
mainfrom
fix/slick-pool-name-13
Jun 23, 2026
Merged

fix(jdbc): unique HikariCP pool name per SlickDatabase provider (#13)#14
fupelaqu merged 1 commit into
mainfrom
fix/slick-pool-name-13

Conversation

@fupelaqu

Copy link
Copy Markdown
Contributor

What & why

Fixes the HikariCP pool-name collision described in #13.

Every SlickDatabase provider (JdbcSchema, JdbcStateProvider,
ColumnMappedJdbcStateProvider, JdbcOffsetProvider, …) builds its own
non-shared HikariCP pool. akka-persistence-jdbc 5.0.4 builds each via
Database.forConfig("slick.db", config), and Slick's HikariCPJdbcDataSource
defaults poolName to the config path → every pool is named slick.db.

In a single JVM this yields multiple distinct pools sharing one name. As soon as
a consumer sets slick.db.registerMbeans = true, only the first pool registers
com.zaxxer.hikari:type=Pool (slick.db); the rest fail with
JMX name (slick.db) is already registered. The same name clash breaks
HikariCP's native Prometheus tracker (collectors are keyed by pool name).

Approach

Approach #1 (unique pool names) from the issue — lowest blast radius, no
lifecycle change.

In SlickDatabase, inject a unique slick.db.poolName into the config before
handing it to SlickExtension(system).database(config):

  • Name format slick.db-<providerClass>-<counter> (JVM AtomicLong counter
    guarantees uniqueness even for multiple instances of the same class).
  • Only injected when a slick.db block is present and no poolName was set
    explicitly (an explicit slick.db.poolName is respected; configs without a
    slick.db block pass through unchanged).
  • Names are sanitized to [A-Za-z0-9._-] so they are valid as a JMX
    ObjectName value and as a Prometheus label.
  • getClass.getSimpleName is guarded with Try (avoids the JDK 8
    InternalError: Malformed class name on synthetic/anonymous classes).

The shared journal/snapshot/read-journal pool (use-shared-db) is built by akka
itself and keeps its own default name — out of scope, and it does not collide
with the new slick.db-… names.

Tests

New SlickDatabasePoolNameSpec (H2, no Docker):

  • distinct HikariCP pool name per provider;
  • an explicitly configured slick.db.poolName is left untouched;
  • with registerMbeans = true, two pools register distinct JMX MBeans.

These assertions fail without the fix (both pools would be named slick.db).

Verification

  • jdbc/scalafmtCheck
  • + jdbc/compile (Scala 2.12.20 + 2.13.16) ✅
  • new spec + existing H2 specs (23 tests) ✅

Acceptance (issue #13)

  • With registerMbeans=true, no already registered ERRORs; one MBean per
    live pool with distinct names.

Addresses #13. (Left open intentionally — not auto-closing via keyword.)

🤖 Generated with Claude Code

Every SlickDatabase provider builds its own non-shared HikariCP pool, and
akka-persistence-jdbc names them all `slick.db` (Database.forConfig("slick.db",
config); Slick defaults poolName to the config path). In a single JVM this
produces multiple pools sharing one name, colliding on JMX MBean registration
once `registerMbeans=true` ("JMX name (slick.db) is already registered") and
breaking HikariCP's Prometheus tracker (keyed by pool name).

Inject a unique `slick.db.poolName` (`slick.db-<providerClass>-<counter>`) per
provider before akka builds the pool, only when a `slick.db` block is present
and no poolName was set explicitly. Names are sanitized to be JMX/Prometheus
safe and `getClass.getSimpleName` is guarded against the JDK 8 InternalError.

Adds SlickDatabasePoolNameSpec (H2): distinct names per provider, explicit
poolName respected, and distinct JMX MBeans under registerMbeans=true.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 0 complexity · 0 duplication

Metric Results
Complexity 0
Duplication 0

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@fupelaqu fupelaqu marked this pull request as ready for review June 23, 2026 17:10
@codecov

codecov Bot commented Jun 23, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.34%. Comparing base (a59c322) to head (526369f).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #14      +/-   ##
==========================================
+ Coverage   61.05%   61.34%   +0.29%     
==========================================
  Files          95       95              
  Lines        1854     1868      +14     
==========================================
+ Hits         1132     1146      +14     
  Misses        722      722              
Flag Coverage Δ
unittests 61.34% <100.00%> (+0.29%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@fupelaqu fupelaqu merged commit 2f02a76 into main Jun 23, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant