// @Test public void testConnectionCloseBlocking() throws SQLException { HikariConfig config = new HikariConfig(); config.setMinimumIdle(0); config.setMaximumPoolSize(1); config.setConnectionTimeout(1500); config.setDataSource(new CustomMockDataSource()); long start = ClockSource.INSTANCE.currentTime(); try (HikariDataSource ds = new HikariDataSource(config)) { Connection connection = ds.getConnection(); connection.close(); // Hikari only checks for validity for connections with lastAccess > 1000 ms so we sleep for // 1001 ms to force // Hikari to do a connection validation which will fail and will trigger the connection to be // closed UtilityElf.quietlySleep(1100L); shouldFail = true; // on physical connection close we sleep 2 seconds connection = ds.getConnection(); Assert.assertTrue( "Waited longer than timeout", (ClockSource.INSTANCE.elapsedMillis(start) < config.getConnectionTimeout())); } catch (SQLException e) { Assert.assertTrue( "getConnection failed because close connection took longer than timeout", (ClockSource.INSTANCE.elapsedMillis(start) < config.getConnectionTimeout())); } }
public PoolBagEntry(final Connection connection, final HikariPool pool) { this.connection = connection; this.parentPool = pool; this.creationTime = System.currentTimeMillis(); this.poolElf = pool.poolElf; this.state = new AtomicInteger(STATE_NOT_IN_USE); this.lastAccess = ClockSource.INSTANCE.currentTime(); this.openStatements = new FastList<>(Statement.class, 16); poolElf.resetPoolEntry(this); final long maxLifetime = pool.config.getMaxLifetime(); final long variance = maxLifetime > 60_000 ? ThreadLocalRandom.current().nextLong(10_000) : 0; final long lifetime = maxLifetime - variance; if (lifetime > 0) { endOfLife = pool.houseKeepingExecutorService.schedule( new Runnable() { @Override public void run() { // If we can reserve it, close it if (pool.connectionBag.reserve(PoolBagEntry.this)) { pool.closeConnection(PoolBagEntry.this, "(connection reached maxLifetime)"); } else { // else the connection is "in-use" and we mark it for eviction by // pool.releaseConnection() or the housekeeper PoolBagEntry.this.evicted = true; } } }, lifetime, TimeUnit.MILLISECONDS); } }
/** {@inheritDoc} */ @Override public String toString() { return String.format( "%s (created %s, last release %dms ago, %s)", connection, formatDateTime(creationTime), ClockSource.INSTANCE.elapsedMillis(lastAccess), stateToString()); }