From 87dc2531fcad9a3ca9e5fb064c6b5559749b2d04 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 16:56:52 -0800 Subject: [PATCH 1/6] PR #1613 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0393b684..83666fd55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Outdated topology during Blue/Green switchover leads to wrong connection failover ([PR #1599](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1599)). - Ensure Blue/Green monitor instances are set up properly ([PR #1612](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1612)). +### :crab: Changed +- Documentation: + - Replace references to AWS JDBC Driver to AWS Advanced JDBC Wrapper for consistency ([PR #1595](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1595)) + - Update instructions regarding MySQL permissions ([PR #1608](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1608)) + +## [2.6.7] - 2025-11-25 + +### :bug: Fixed +- Handle nested auth exceptions in MySQLExceptionHandler ([PR #1601](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1601)) and in other handlers ([PR #1605](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1605)). +- Outdated topology during Blue/Green switchover leads to wrong connection failover ([PR #1599](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1599)). +- Ensure Blue/Green monitor instances are set up properly ([PR #1612](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1612)). + ### :crab: Changed - Documentation: - Replace references to AWS JDBC Driver to AWS Advanced JDBC Wrapper for consistency ([PR #1595](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1595)) From 41fd59f8cdffd00e2c59d569cd91eb1ee598cf01 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 17:03:56 -0800 Subject: [PATCH 2/6] PR #1616 --- .../CustomEndpointMonitorImpl.java | 42 +++++++++++++++---- .../CustomEndpointMonitorImplTest.java | 3 +- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/wrapper/src/main/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImpl.java b/wrapper/src/main/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImpl.java index 77666c307..09ac17a90 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImpl.java +++ b/wrapper/src/main/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImpl.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.BiFunction; import java.util.logging.Level; import java.util.logging.Logger; @@ -51,9 +52,10 @@ public class CustomEndpointMonitorImpl extends AbstractMonitor implements Custom // Keys are custom endpoint URLs, values are information objects for the associated custom endpoint. protected static final CacheMap customEndpointInfoCache = new CacheMap<>(); protected static final long CUSTOM_ENDPOINT_INFO_EXPIRATION_NANO = TimeUnit.MINUTES.toNanos(5); - protected static final long UNAUTHORIZED_SLEEP_SEC = TimeUnit.MINUTES.toSeconds(5); + protected static final long UNAUTHORIZED_SLEEP_NANO = TimeUnit.MINUTES.toNanos(5); protected static final long MONITOR_TERMINATION_TIMEOUT_SEC = 30; + protected final AtomicBoolean refreshRequired = new AtomicBoolean(false); protected final RdsClient rdsClient; protected final HostSpec customEndpointHostSpec; protected final String endpointIdentifier; @@ -133,7 +135,7 @@ public void monitor() { } )); - TimeUnit.NANOSECONDS.sleep(this.refreshRateNano); + this.sleep(this.refreshRateNano); continue; } @@ -142,7 +144,7 @@ public void monitor() { if (cachedEndpointInfo != null && cachedEndpointInfo.equals(endpointInfo)) { long elapsedTime = System.nanoTime() - start; long sleepDuration = Math.max(0, this.refreshRateNano - elapsedTime); - TimeUnit.NANOSECONDS.sleep(sleepDuration); + this.sleep(sleepDuration); continue; } @@ -162,13 +164,14 @@ public void monitor() { this.storageService.set(this.customEndpointHostSpec.getUrl(), allowedAndBlockedHosts); customEndpointInfoCache.put( this.customEndpointHostSpec.getUrl(), endpointInfo, CUSTOM_ENDPOINT_INFO_EXPIRATION_NANO); + this.refreshRequired.set(false); if (this.infoChangedCounter != null) { this.infoChangedCounter.inc(); } long elapsedTime = System.nanoTime() - start; long sleepDuration = Math.max(0, this.refreshRateNano - elapsedTime); - TimeUnit.NANOSECONDS.sleep(sleepDuration); + this.sleep(sleepDuration); } catch (InterruptedException e) { throw e; } catch (RdsException ex) { @@ -179,13 +182,13 @@ public void monitor() { if (ex.isThrottlingException()) { this.refreshRateNano *= 2; // Reduce the refresh rate. - TimeUnit.NANOSECONDS.sleep(this.refreshRateNano); + this.sleep(this.refreshRateNano); } else if (ex.statusCode() == HttpStatusCode.UNAUTHORIZED || ex.statusCode() == HttpStatusCode.FORBIDDEN) { // User has no permissions to get custom endpoint details. // Reduce the refresh rate. - TimeUnit.SECONDS.sleep(UNAUTHORIZED_SLEEP_SEC); + this.sleep(UNAUTHORIZED_SLEEP_NANO); } else { - TimeUnit.NANOSECONDS.sleep(this.refreshRateNano); + this.sleep(this.refreshRateNano); } } catch (Exception e) { // If the exception is not an InterruptedException, log it and continue monitoring. @@ -194,7 +197,7 @@ public void monitor() { "CustomEndpointMonitorImpl.exception", new Object[] {this.customEndpointHostSpec.getUrl()}), e); - TimeUnit.NANOSECONDS.sleep(this.refreshRateNano); + this.sleep(this.refreshRateNano); } } } catch (InterruptedException e) { @@ -213,8 +216,29 @@ public void monitor() { } } + protected void sleep(long durationNano) throws InterruptedException { + long endNano = System.nanoTime() + durationNano; + // Choose the minimum between 500ms and the durationNano passed in, in case durationNano is less than 500ms. + long waitDurationMs = Math.min(500, TimeUnit.NANOSECONDS.toMillis(durationNano)); + while (!this.refreshRequired.get() && System.nanoTime() < endNano && !this.stop.get()) { + synchronized (this.refreshRequired) { + this.refreshRequired.wait(waitDurationMs); + } + } + } + public boolean hasCustomEndpointInfo() { - return customEndpointInfoCache.get(this.customEndpointHostSpec.getUrl()) != null; + CustomEndpointInfo customEndpointInfo = customEndpointInfoCache.get(this.customEndpointHostSpec.getUrl()); + if (customEndpointInfo == null && !this.refreshRequired.get()) { + // There is no custom endpoint info, probably because the cache entry has expired. We use notifyAll below to + // wake up the custom endpoint monitor if it is sleeping. + synchronized (this.refreshRequired) { + this.refreshRequired.set(true); + this.refreshRequired.notifyAll(); + } + } + + return customEndpointInfo != null; } @Override diff --git a/wrapper/src/test/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImplTest.java b/wrapper/src/test/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImplTest.java index 8a4d5395b..2e6c3bc9a 100644 --- a/wrapper/src/test/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImplTest.java +++ b/wrapper/src/test/java/software/amazon/jdbc/plugin/customendpoint/CustomEndpointMonitorImplTest.java @@ -33,13 +33,13 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; import java.util.function.Consumer; +import org.checkerframework.checker.nullness.qual.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.testcontainers.shaded.org.checkerframework.checker.nullness.qual.Nullable; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rds.RdsClient; import software.amazon.awssdk.services.rds.model.DBClusterEndpoint; @@ -49,7 +49,6 @@ import software.amazon.jdbc.HostSpecBuilder; import software.amazon.jdbc.hostavailability.HostAvailabilityStrategy; import software.amazon.jdbc.hostavailability.SimpleHostAvailabilityStrategy; -import software.amazon.jdbc.util.monitoring.MonitorService; import software.amazon.jdbc.util.storage.StorageService; import software.amazon.jdbc.util.telemetry.TelemetryCounter; import software.amazon.jdbc.util.telemetry.TelemetryFactory; From 3b8f9d7d8ff01e6f331594b7336911a5c74c6201 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 17:11:04 -0800 Subject: [PATCH 3/6] PR #1624 --- .../ClusterTopologyMonitorImpl.java | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java index 845ef1c5f..5a4baa9a2 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java +++ b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java @@ -237,7 +237,11 @@ private List getStoredHosts() { @Override public void stop() { this.nodeThreadsStop.set(true); - this.shutdownNodeExecutorService(); + + this.closeNodeMonitors(); + this.closeConnection(this.nodeThreadsWriterConnection); + this.closeConnection(this.nodeThreadsReaderConnection); + this.closeConnection(this.monitoringConnection); // This code interrupts the waiting/sleeping cycle in the monitoring thread. synchronized (this.requestToUpdateTopology) { @@ -250,6 +254,7 @@ public void stop() { @Override public void close() { + this.closeNodeMonitors(); this.closeConnection(this.monitoringConnection); this.closeConnection(this.nodeThreadsWriterConnection); this.closeConnection(this.nodeThreadsReaderConnection); @@ -277,8 +282,7 @@ public void monitor() throws Exception { // Start node monitors. this.nodeThreadsStop.set(false); - this.nodeThreadsWriterConnection.set(null); - this.nodeThreadsReaderConnection.set(null); + this.nodeThreadConnectionCleanUp(); this.nodeThreadsWriterHostSpec.set(null); this.nodeThreadsLatestTopology.set(null); @@ -288,7 +292,7 @@ public void monitor() throws Exception { hosts = this.openAnyConnectionAndUpdateTopology(); } - this.shutdownNodeExecutorService(); + this.closeNodeMonitors(); this.createNodeExecutorService(); if (hosts != null && !this.isVerifiedWriterConnection) { @@ -341,7 +345,7 @@ public void monitor() throws Exception { } this.nodeThreadsStop.set(true); - this.shutdownNodeExecutorService(); + this.closeNodeMonitors(); this.submittedNodes.clear(); continue; @@ -381,7 +385,7 @@ public void monitor() throws Exception { } else { // We are in regular mode (not panic mode). if (!this.submittedNodes.isEmpty()) { - this.shutdownNodeExecutorService(); + this.closeNodeMonitors(); this.submittedNodes.clear(); } @@ -390,6 +394,7 @@ public void monitor() throws Exception { // Attempt to fetch topology failed, so we switch to panic mode. this.closeConnection(this.monitoringConnection); this.isVerifiedWriterConnection = false; + this.writerHostSpec.set(null); continue; } @@ -428,11 +433,9 @@ public void monitor() throws Exception { throw ex; } finally { this.stop.set(true); - this.shutdownNodeExecutorService(); - - final Connection conn = this.monitoringConnection.get(); - this.monitoringConnection.set(null); - this.closeConnection(conn); + this.closeNodeMonitors(); + this.closeConnection(this.monitoringConnection); + this.nodeThreadConnectionCleanUp(); this.servicesContainer.getEventPublisher().unsubscribe( this, Collections.singleton(MonitorResetEvent.class)); @@ -448,14 +451,13 @@ protected void reset() { new Object[]{this.clusterId, this.initialHostSpec.getHost()})); this.nodeThreadsStop.set(true); - this.shutdownNodeExecutorService(); + this.closeNodeMonitors(); + this.nodeThreadConnectionCleanUp(); this.nodeThreadsStop.set(false); this.submittedNodes.clear(); this.createNodeExecutorService(); - this.nodeThreadsWriterConnection.set(null); this.nodeThreadsWriterHostSpec.set(null); - this.nodeThreadsReaderConnection.set(null); this.nodeThreadsLatestTopology.set(null); this.closeConnection(this.monitoringConnection); @@ -484,7 +486,20 @@ public void processEvent(Event event) { } } - protected void shutdownNodeExecutorService() { + protected void nodeThreadConnectionCleanUp() { + if (this.monitoringConnection.get() != this.nodeThreadsWriterConnection.get()) { + this.closeConnection(this.nodeThreadsWriterConnection); + } else { + this.nodeThreadsWriterConnection.set(null); + } + if (this.monitoringConnection.get() != this.nodeThreadsReaderConnection.get()) { + this.closeConnection(this.nodeThreadsReaderConnection); + } else { + this.nodeThreadsReaderConnection.set(null); + } + } + + protected void closeNodeMonitors() { if (this.nodeExecutorService != null) { this.nodeExecutorLock.lock(); @@ -507,6 +522,8 @@ protected void shutdownNodeExecutorService() { } this.nodeExecutorService = null; + this.nodeThreadConnectionCleanUp(); + } finally { this.nodeExecutorLock.unlock(); } @@ -600,6 +617,7 @@ protected List openAnyConnectionAndUpdateTopology() { // Attempt to fetch topology failed. There might be something wrong with the connection, so we close it here. this.closeConnection(this.monitoringConnection); this.isVerifiedWriterConnection = false; + this.writerHostSpec.set(null); } return hosts; @@ -790,12 +808,10 @@ public void run() { // be established. if (updateTopology) { this.readerThreadFetchTopology(connection, this.writerHostSpec); - } else if (this.monitor.nodeThreadsReaderConnection.get() == null) { - if (this.monitor.nodeThreadsReaderConnection.compareAndSet(null, connection)) { - // Use this connection to update the topology. - updateTopology = true; - this.readerThreadFetchTopology(connection, this.writerHostSpec); - } + } else if (this.monitor.nodeThreadsReaderConnection.compareAndSet(null, connection)) { + // Use this connection to update the topology. + updateTopology = true; + this.readerThreadFetchTopology(connection, this.writerHostSpec); } } } From 792947d2e98e9a38e3ab2a9f4fc947ec381c5f01 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 17:14:45 -0800 Subject: [PATCH 4/6] PR #1621 --- .../exceptions/MySQLExceptionHandler.java | 3 +- .../jdbc/exceptions/PgExceptionHandler.java | 1 - .../ClusterTopologyMonitorImpl.java | 35 ++++++++++++++++--- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/wrapper/src/main/java/software/amazon/jdbc/exceptions/MySQLExceptionHandler.java b/wrapper/src/main/java/software/amazon/jdbc/exceptions/MySQLExceptionHandler.java index feb98fe38..11eaa3777 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/exceptions/MySQLExceptionHandler.java +++ b/wrapper/src/main/java/software/amazon/jdbc/exceptions/MySQLExceptionHandler.java @@ -73,7 +73,8 @@ public boolean isNetworkException(final String sqlState) { return false; } - return sqlState.startsWith("08"); + // 08004 - "Server rejected the connection" or "Connection refused by server" + return sqlState.startsWith("08") && !"08004".equals(sqlState); } @Override diff --git a/wrapper/src/main/java/software/amazon/jdbc/exceptions/PgExceptionHandler.java b/wrapper/src/main/java/software/amazon/jdbc/exceptions/PgExceptionHandler.java index 2b887167a..c43d77379 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/exceptions/PgExceptionHandler.java +++ b/wrapper/src/main/java/software/amazon/jdbc/exceptions/PgExceptionHandler.java @@ -23,7 +23,6 @@ public class PgExceptionHandler extends AbstractPgExceptionHandler { // The following SQL States for Postgresql are considered as "communication" errors private static final List NETWORK_ERRORS = Arrays.asList( - "53", // insufficient resources "57P01", // admin shutdown "57P02", // crash shutdown "57P03", // cannot connect now diff --git a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java index 5a4baa9a2..ff5c4b244 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java +++ b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/monitoring/ClusterTopologyMonitorImpl.java @@ -21,10 +21,9 @@ import java.sql.SQLSyntaxErrorException; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; import java.util.List; import java.util.Properties; +import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; @@ -73,6 +72,10 @@ public class ClusterTopologyMonitorImpl extends AbstractMonitor implements Clust protected static final long highRefreshPeriodAfterPanicNano = TimeUnit.SECONDS.toNanos(30); protected static final long ignoreTopologyRequestNano = TimeUnit.SECONDS.toNanos(10); + private static final long INITIAL_BACKOFF_MS = 100; + private static final long MAX_BACKOFF_MS = 10000; + private static final Random random = new Random(); + protected final AtomicReference writerHostSpec = new AtomicReference<>(null); protected final AtomicReference monitoringConnection = new AtomicReference<>(null); @@ -720,6 +723,7 @@ private static class NodeMonitoringWorker implements Runnable { protected final HostSpec hostSpec; protected final @Nullable HostSpec writerHostSpec; protected boolean writerChanged = false; + protected int connectionAttempts = 0; public NodeMonitoringWorker( final FullServicesContainer servicesContainer, @@ -747,10 +751,25 @@ public void run() { try { connection = this.servicesContainer.getPluginService().forceConnect( hostSpec, this.monitor.monitoringProperties); + this.connectionAttempts = 0; } catch (SQLException ex) { - // A problem occurred while connecting. We will try again on the next iteration. - TimeUnit.MILLISECONDS.sleep(100); - continue; + // A problem occurred while connecting. + if (this.servicesContainer.getPluginService().isNetworkException( + ex, this.servicesContainer.getPluginService().getTargetDriverDialect())) { + // It's a network issue that's expected during a cluster failover. + // We will try again on the next iteration. + TimeUnit.MILLISECONDS.sleep(100); + continue; + } else if (this.servicesContainer.getPluginService().isLoginException( + ex, this.servicesContainer.getPluginService().getTargetDriverDialect())) { + // Something wrong with login credentials. We can't continue. + throw new RuntimeException(ex); + } else { + // It might be some transient error. Let's try again. + // If the error repeats, we will try again after a longer delay. + TimeUnit.MILLISECONDS.sleep(this.calculateBackoffWithJitter(this.connectionAttempts++)); + continue; + } } } @@ -874,5 +893,11 @@ private void readerThreadFetchTopology(final Connection connection, final @Nulla LOGGER.fine(() -> LogUtils.logTopology(hosts)); } } + + private long calculateBackoffWithJitter(int attempt) { + long backoff = INITIAL_BACKOFF_MS * Math.round(Math.pow(2, Math.min(attempt, 6))); + backoff = Math.min(backoff, MAX_BACKOFF_MS); + return Math.round(backoff * (0.5 + random.nextDouble() * 0.5)); + } } } From d73dc2d40eac8b964c07175640d3760c3f254323 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 17:21:37 -0800 Subject: [PATCH 5/6] PR #1629 --- CHANGELOG.md | 16 +++++++++------- Maintenance.md | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83666fd55..66749208e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,17 +25,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### :magic_wand: Added - Added support of Global Databases including and Global Database endpoint. ([PR #1573](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1573)). -## [2.6.7] - 2025-11-25 + +## [2.6.8] - 2025-12-04 ### :bug: Fixed -- Handle nested auth exceptions in MySQLExceptionHandler ([PR #1601](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1601)) and in other handlers ([PR #1605](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1605)). -- Outdated topology during Blue/Green switchover leads to wrong connection failover ([PR #1599](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1599)). -- Ensure Blue/Green monitor instances are set up properly ([PR #1612](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1612)). +- Wait timeout for custom endpoint info ([PR #1616](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1616)) +- Use custom endpoint as cluster ID to prevent accumulating of connections if using a custom endpoint in a connection string ([PR #1619](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1619)) ### :crab: Changed -- Documentation: - - Replace references to AWS JDBC Driver to AWS Advanced JDBC Wrapper for consistency ([PR #1595](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1595)) - - Update instructions regarding MySQL permissions ([PR #1608](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1608)) +- Improve exception handling when DB server reaches maximum available connections ([PR #1621](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1621)) +- Improve connection management to prevent connection leaking in topology monitor ([PR #1624](https://github.com/aws/aws-advanced-jdbc-wrapper/pull/1624)) ## [2.6.7] - 2025-11-25 @@ -594,6 +593,9 @@ The Amazon Web Services (AWS) Advanced JDBC Driver allows an application to take - The [AWS IAM Authentication Connection Plugin](./docs/using-the-jdbc-driver/using-plugins/UsingTheIamAuthenticationPlugin.md) - The [AWS Secrets Manager Connection Plugin](./docs/using-the-jdbc-driver/using-plugins/UsingTheAwsSecretsManagerPlugin.md) +[2.6.8]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.7...2.6.8 +[2.6.7]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.6...2.6.7 +[2.6.6]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.5...2.6.6 [2.6.5]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.4...2.6.5 [2.6.4]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.3...2.6.4 [2.6.3]: https://github.com/aws/aws-advanced-jdbc-wrapper/compare/2.6.2...2.6.3 diff --git a/Maintenance.md b/Maintenance.md index 20fa5a983..5deeb0e33 100644 --- a/Maintenance.md +++ b/Maintenance.md @@ -40,6 +40,7 @@ | October 16, 2025 | [Release 2.6.5](https://github.com/aws/aws-advanced-jdbc-wrapper/releases/tag/2.6.5) | | November 5, 2025 | [Release 2.6.6](https://github.com/aws/aws-advanced-jdbc-wrapper/releases/tag/2.6.6) | | November 25, 2025 | [Release 2.6.7](https://github.com/aws/aws-advanced-jdbc-wrapper/releases/tag/2.6.7) | +| December 4, 2025 | [Release 2.6.8](https://github.com/aws/aws-advanced-jdbc-wrapper/releases/tag/2.6.8) | `aws-advanced-jdbc-wrapper` [follows semver](https://semver.org/#semantic-versioning-200) which means we will only release breaking changes in major versions. Generally speaking patches will be released to fix existing problems without @@ -93,5 +94,5 @@ from the updated source after the PRs are merged. | Major Version | Latest Minor Version | Status | Initial Release | Maintenance Window Start | Maintenance Window End | |---------------|----------------------|-------------|-----------------|--------------------------|------------------------| | 1 | 1.0.2 | Maintenance | Oct 5, 2022 | Apr 28, 2023 | Apr 28, 2024 | -| 2 | 2.6.7 | Maintenance | Jan 1, 2026 | Dec 31, 2026 | N/A | +| 2 | 2.6.8 | Maintenance | Apr 28, 2023 | Dec 31, 2026 | N/A | | 3 | 3.0.0 | Current | Dec 12, 2025 | N/A | N/A | From 4dbb356298c6727b2dcf38e44940377c036b1d45 Mon Sep 17 00:00:00 2001 From: sergiyvamz Date: Mon, 8 Dec 2025 17:32:45 -0800 Subject: [PATCH 6/6] PR #1624 --- .../hostlistprovider/GlobalAuroraTopologyUtils.java | 6 ++++-- .../amazon/jdbc/hostlistprovider/TopologyUtils.java | 12 ++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/GlobalAuroraTopologyUtils.java b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/GlobalAuroraTopologyUtils.java index 4a5d5eeea..081e24d02 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/GlobalAuroraTopologyUtils.java +++ b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/GlobalAuroraTopologyUtils.java @@ -55,7 +55,9 @@ public GlobalAuroraTopologyUtils(GlobalAuroraTopologyDialect dialect, HostSpecBu public @Nullable List queryForTopology( Connection conn, HostSpec initialHostSpec, Map instanceTemplatesByRegion) throws SQLException { - int originalNetworkTimeout = setNetworkTimeout(conn); + final Pair networkTimeoutPair = this.setNetworkTimeout(conn); + int originalNetworkTimeout = networkTimeoutPair.getValue1(); + boolean timeoutChanged = networkTimeoutPair.getValue2(); try (final Statement stmt = conn.createStatement(); final ResultSet rs = stmt.executeQuery(this.dialect.getTopologyQuery())) { if (rs.getMetaData().getColumnCount() == 0) { @@ -68,7 +70,7 @@ public GlobalAuroraTopologyUtils(GlobalAuroraTopologyDialect dialect, HostSpecBu } catch (final SQLSyntaxErrorException e) { throw new SQLException(Messages.get("TopologyUtils.invalidQuery"), e); } finally { - if (originalNetworkTimeout == 0 && !conn.isClosed()) { + if (timeoutChanged && !conn.isClosed()) { conn.setNetworkTimeout(networkTimeoutExecutor, originalNetworkTimeout); } } diff --git a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/TopologyUtils.java b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/TopologyUtils.java index 5a6a2ef68..84a0ea8e5 100644 --- a/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/TopologyUtils.java +++ b/wrapper/src/main/java/software/amazon/jdbc/hostlistprovider/TopologyUtils.java @@ -71,7 +71,9 @@ public TopologyUtils( */ public @Nullable List queryForTopology(Connection conn, HostSpec initialHostSpec, HostSpec instanceTemplate) throws SQLException { - int originalNetworkTimeout = setNetworkTimeout(conn); + final Pair networkTimeoutPair = this.setNetworkTimeout(conn); + int originalNetworkTimeout = networkTimeoutPair.getValue1(); + boolean timeoutChanged = networkTimeoutPair.getValue2(); try (final Statement stmt = conn.createStatement(); final ResultSet rs = stmt.executeQuery(this.dialect.getTopologyQuery())) { if (rs.getMetaData().getColumnCount() == 0) { @@ -84,24 +86,26 @@ public TopologyUtils( } catch (final SQLSyntaxErrorException e) { throw new SQLException(Messages.get("TopologyUtils.invalidQuery"), e); } finally { - if (originalNetworkTimeout == 0 && !conn.isClosed()) { + if (timeoutChanged && !conn.isClosed()) { conn.setNetworkTimeout(networkTimeoutExecutor, originalNetworkTimeout); } } } - protected int setNetworkTimeout(Connection conn) { + protected Pair setNetworkTimeout(Connection conn) { int networkTimeout = -1; + boolean timeoutChanged = false; try { networkTimeout = conn.getNetworkTimeout(); // The topology query is not monitored by the EFM plugin, so it needs a socket timeout. if (networkTimeout == 0) { conn.setNetworkTimeout(this.networkTimeoutExecutor, DEFAULT_QUERY_TIMEOUT_MS); + timeoutChanged = true; } } catch (SQLException e) { LOGGER.warning(() -> Messages.get("TopologyUtils.errorGettingNetworkTimeout", new Object[] {e.getMessage()})); } - return networkTimeout; + return Pair.create(networkTimeout, timeoutChanged); } protected abstract @Nullable List getHosts(