diff --git a/src/main/java/com/zaxxer/hikari/HikariConfig.java b/src/main/java/com/zaxxer/hikari/HikariConfig.java index 92c20577f..e50c16e8d 100644 --- a/src/main/java/com/zaxxer/hikari/HikariConfig.java +++ b/src/main/java/com/zaxxer/hikari/HikariConfig.java @@ -53,6 +53,7 @@ public class HikariConfig implements HikariConfigMXBean private static final long SOFT_TIMEOUT_FLOOR = Long.getLong("com.zaxxer.hikari.timeoutMs.floor", 250L); private static final long IDLE_TIMEOUT = MINUTES.toMillis(10); private static final long MAX_LIFETIME = MINUTES.toMillis(30); + private static final double DEFAULT_MAX_LIFETIME_VARIANCE = 2.5; private static final long DEFAULT_KEEPALIVE_TIME = 0L; private static final int DEFAULT_POOL_SIZE = 10; @@ -66,6 +67,7 @@ public class HikariConfig implements HikariConfigMXBean private volatile long idleTimeout; private volatile long leakDetectionThreshold; private volatile long maxLifetime; + private volatile double maxLifetimeVariance; private volatile int maxPoolSize; private volatile int minIdle; private volatile String username; @@ -119,6 +121,7 @@ public HikariConfig() minIdle = -1; maxPoolSize = -1; maxLifetime = MAX_LIFETIME; + maxLifetimeVariance = DEFAULT_MAX_LIFETIME_VARIANCE; connectionTimeout = CONNECTION_TIMEOUT; validationTimeout = VALIDATION_TIMEOUT; idleTimeout = IDLE_TIMEOUT; @@ -229,6 +232,17 @@ public void setLeakDetectionThreshold(long leakDetectionThresholdMs) this.leakDetectionThreshold = leakDetectionThresholdMs; } + /** {@inheritDoc} */ + @Override + public double getMaxLifetimeVariance() + { + return maxLifetimeVariance; + } + + /** {@inheritDoc} */ + @Override + public void setMaxLifetimeVariance(double maxLifetimeVariance) { this.maxLifetimeVariance = maxLifetimeVariance; } + /** {@inheritDoc} */ @Override public long getMaxLifetime() diff --git a/src/main/java/com/zaxxer/hikari/HikariConfigMXBean.java b/src/main/java/com/zaxxer/hikari/HikariConfigMXBean.java index 2e510d533..9fd12eb6d 100644 --- a/src/main/java/com/zaxxer/hikari/HikariConfigMXBean.java +++ b/src/main/java/com/zaxxer/hikari/HikariConfigMXBean.java @@ -93,6 +93,24 @@ public interface HikariConfigMXBean */ void setLeakDetectionThreshold(long leakDetectionThresholdMs); + /** + * This property controls the percentage of a connections maximum lifetime that will be used as variance/jitter. + * This percentage will be a maximum and random variances up to this percentage will be subtracted from the defined + * maxLifeTime value. + * + * @return the maximum percentage of a connections maxLifeTime to be utilized as a variance + */ + double getMaxLifetimeVariance(); + + /** + * This property controls the percentage of a connections maximum lifetime that will be used as variance/jitter. + * This percentage will be a maximum and random variances up to this percentage will be subtracted from the defined + * maxLifeTime value. + * + * @param maxLifetimeVariance the maximum percentage of maxLifeTime that should be used for variance + */ + void setMaxLifetimeVariance(double maxLifetimeVariance); + /** * This property controls the maximum lifetime of a connection in the pool. When a connection reaches this * timeout, even if recently used, it will be retired from the pool. An in-use connection will never be diff --git a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java index 077120551..1aa4090ee 100644 --- a/src/main/java/com/zaxxer/hikari/pool/HikariPool.java +++ b/src/main/java/com/zaxxer/hikari/pool/HikariPool.java @@ -452,7 +452,7 @@ int[] getPoolStateCounts() // *********************************************************************** /** - * Creating new poolEntry. If maxLifetime is configured, create a future End-of-life task with 2.5% variance from + * Creating new poolEntry. If maxLifetime is configured, create a future End-of-life task with configurable variance from * the maxLifetime time to ensure there is no massive die-off of Connections in the pool. */ private PoolEntry createPoolEntry() @@ -462,8 +462,7 @@ private PoolEntry createPoolEntry() final var maxLifetime = config.getMaxLifetime(); if (maxLifetime > 0) { - // variance up to 2.5% of the maxlifetime - final var variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( maxLifetime / 40 ) : 0; + final var variance = maxLifetime > 10_000 ? ThreadLocalRandom.current().nextLong( Math.round(maxLifetime * (config.getMaxLifetimeVariance() / 100)) ) : 0; final var lifetime = maxLifetime - variance; poolEntry.setFutureEol(houseKeepingExecutorService.schedule(new MaxLifetimeTask(poolEntry), lifetime, MILLISECONDS)); } diff --git a/src/main/java/com/zaxxer/hikari/util/PropertyElf.java b/src/main/java/com/zaxxer/hikari/util/PropertyElf.java index 9cebdfbab..a2e497b52 100644 --- a/src/main/java/com/zaxxer/hikari/util/PropertyElf.java +++ b/src/main/java/com/zaxxer/hikari/util/PropertyElf.java @@ -138,6 +138,9 @@ else if (paramClass == long.class) { else if (paramClass == short.class) { writeMethod.invoke(target, Short.parseShort(propValue.toString())); } + else if (paramClass == double.class) { + writeMethod.invoke(target, Double.parseDouble(propValue.toString())); + } else if (paramClass == boolean.class || paramClass == Boolean.class) { writeMethod.invoke(target, Boolean.parseBoolean(propValue.toString())); }