diff --git a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index a7b21ec47..968df12a5 100644 --- a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -705,14 +705,18 @@ private SQLException createTimeoutException(long startTime) String sqlState = null; int errorCode = 0; final var originalException = getLastConnectionFailure(); + Long lastConnectionFailureTimestamp = getLastConnectionFailureTimestamp(); if (originalException instanceof SQLException) { sqlState = ((SQLException) originalException).getSQLState(); errorCode = ((SQLException) originalException).getErrorCode(); } - final var connectionException = new SQLTransientConnectionException( - poolName + " - Connection is not available, request timed out after " + elapsedMillis(startTime) + "ms " + - "(total=" + getTotalConnections() + ", active=" + getActiveConnections() + ", idle=" + getIdleConnections() + ", waiting=" + getThreadsAwaitingConnection() + ")", - sqlState, errorCode, originalException); + String errorDescription = poolName + " - Connection is not available, request timed out after " + elapsedMillis(startTime) + "ms " + + "(total=" + getTotalConnections() + ", active=" + getActiveConnections() + ", idle=" + getIdleConnections() + ", waiting=" + getThreadsAwaitingConnection() + ")"; + if (lastConnectionFailureTimestamp != null && lastConnectionFailureTimestamp != 0) { + errorDescription += " - The last connection failure (appended as the next exception below) happened " + + elapsedDisplayString(lastConnectionFailureTimestamp, currentTime()) + " ago."; + } + final var connectionException = new SQLTransientConnectionException(errorDescription, sqlState, errorCode, originalException); if (originalException instanceof SQLException) { connectionException.setNextException((SQLException) originalException); } diff --git a/src/main/java/com/zaxxer/hikari/pool/PoolBase.java b/src/main/java/com/zaxxer/hikari/pool/PoolBase.java index 803f4bbbd..bc49cd1af 100644 --- a/src/main/java/com/zaxxer/hikari/pool/PoolBase.java +++ b/src/main/java/com/zaxxer/hikari/pool/PoolBase.java @@ -62,6 +62,7 @@ abstract class PoolBase volatile String catalog; final AtomicReference lastConnectionFailure; + final AtomicLong lastConnectionFailureTimestamp; final AtomicLong connectionFailureTimestamp; long connectionTimeout; @@ -116,6 +117,7 @@ abstract class PoolBase this.connectionTimeout = config.getConnectionTimeout(); this.validationTimeout = config.getValidationTimeout(); this.lastConnectionFailure = new AtomicReference<>(); + this.lastConnectionFailureTimestamp = new AtomicLong(); this.connectionFailureTimestamp = new AtomicLong(); initializeDataSource(); @@ -185,6 +187,7 @@ boolean isConnectionDead(final Connection connection) } catch (Exception e) { lastConnectionFailure.set(e); + lastConnectionFailureTimestamp.set(currentTime()); logger.warn("{} - Failed to validate connection {} ({}). Possibly consider using a shorter maxLifetime value.", poolName, connection, e.getMessage()); return true; @@ -196,6 +199,10 @@ Throwable getLastConnectionFailure() return lastConnectionFailure.get(); } + Long getLastConnectionFailureTimestamp(){ + return lastConnectionFailureTimestamp.get(); + } + public DataSource getUnwrappedDataSource() { return dataSource; @@ -378,6 +385,7 @@ private Connection newConnection(final boolean isEmptyPool) throws Exception setupConnection(connection); lastConnectionFailure.set(null); + lastConnectionFailureTimestamp.set(0); connectionFailureTimestamp.set(0); logger.debug("{} - Established new connection ({})", poolName, id); @@ -397,6 +405,7 @@ private Connection newConnection(final boolean isEmptyPool) throws Exception } lastConnectionFailure.set(t); + lastConnectionFailureTimestamp.set(currentTime()); throw t; } finally {