Skip to content

AWS Advanced JDBC Wrapper integration

common-module’s DataSource integrates the AWS Advanced JDBC Wrapper (4.x) so that consumers can opt into Aurora reader-instance routing for read-only transactions and topology-driven failover detection. Adoption is scheme-detected per consumer — flip a single configuration string to opt in.

CapabilityWithout wrapper (jdbc:postgresql:)With wrapper (jdbc:aws-wrapper:postgresql:)
Read-only transactionsAll hit the writer endpoint.Auto-routed to Aurora reader instances via the readWriteSplitting plugin.
Failover detection latency~30 s, bounded by the JVM DNS cache TTL.~2–5 s, via Aurora’s topology API (failover2 plugin).
Failover exception surfaceGeneric PSQLException → HTTP 500.Typed FailoverSuccess / TransactionStateUnknown / FailoverFailed exceptions → mapped to AppError.TransientHTTP 503 + Retry-After: 2 (see API design — Transient failures and retry contract). Most failovers are absorbed by the in-process retry at the inTransaction boundary and the caller sees HTTP 200.

Set the consumer’s jdbcUrl to the wrapper scheme. Everything else is read by common-module from the URL prefix. No other configuration knob is required.

# application.conf — opted in
dataSource {
db {
url = "jdbc:aws-wrapper:postgresql://<cluster-endpoint>:5432/<db>"
}
}
# application.conf — not opted in (zero behaviour change)
dataSource {
db {
url = "jdbc:postgresql://<cluster-endpoint>:5432/<db>"
}
}

The retry policy at the inTransaction boundary picks up dataSource.pool.maxAttempts (default 2) and dataSource.pool.backoffMs (default 300 ms) regardless of the URL scheme — but it only triggers when classification returns AppError.Transient, which can only happen when the wrapper is opted in.

common-module’s DataSource detects the wrapper scheme and conditionally wires HikariCP through the wrapper:

PlantUML diagram

The wrapper is a JDBC driver that sits between HikariCP and the PostgreSQL driver. It intercepts Connection.setReadOnly(boolean) (which Exposed already calls when application code passes readOnly = true to transaction(...)), and re-routes the physical connection accordingly. When the cluster topology changes, the wrapper raises typed exceptions that common-module classifies via Throwable.normalizeToAppError() into AppError.Transient subtypes.

The wrapper-specific HikariCP configuration (driver class, wrapperPlugins, exceptionOverrideClassName, Aurora tuning properties) is only set when isWrapperScheme = dbConfig.url.toString().startsWith("jdbc:aws-wrapper:") is true. Consumers on jdbc:postgresql: URLs run the same HikariCP setup as before PDEV-490.

ComponentOpted in?Notes
operationsYes (PDEV-490)All module DBs (kanban, item, facility, station, business-affiliates, procurement-orders, batch) opt in via the Helm jdbcUrlFor template.
accounts-componentNoMigration deferred until a similar performance / resilience driver appears.

New consumers can opt in unilaterally — there is no coordination with common-module beyond depending on 8.4.0 or later.

  • First-request topology discovery cost. The wrapper’s topology cache is built lazily on first use. The first request after a pod cold start may pay a ~50–100 ms topology-discovery cost. auroraInitialConnection plugin in the pipeline keeps this bounded; failoverClusterTopologyRefreshRateMs = 2000 keeps the cache fresh thereafter.
  • HikariCP cooperation. exceptionOverrideClassName = software.amazon.jdbc.util.HikariCPSQLException is set when opted in; this tells HikariCP to keep connections alive that the wrapper marks as recoverable (e.g. during a failover window). Without this, HikariCP would evict the pool on every transient SQL exception and pay full reconnect cost.
  • RDS Proxy is incompatible. The wrapper expects direct connections to Aurora cluster endpoints; routing through RDS Proxy bypasses the topology discovery and read-write splitting. PDEV-499 closed RDS Proxy adoption as won’t-do for this reason.

Copyright: (c) Arda Systems 2025-2026, All rights reserved