Files
hibernate-demo/src/test/java/com/ankurm/hibernatedemo/hikari/HikariPoolExhaustionTest.java
T

85 lines
3.1 KiB
Java

package com.ankurm.hibernatedemo.hikari;
import static org.assertj.core.api.Assertions.assertThat;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLTransientConnectionException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
/**
* The failure mode a pool-sizing article should lead with: what actually happens when every
* connection in the pool is checked out and something else asks for one more. Not "it blocks
* forever" and not a generic timeout -- HikariCP throws a specific, named exception with the pool
* name and the timeout value baked into the message.
*
* <p>Docs: docs/19-hikaricp-connection-pooling.md
*/
class HikariPoolExhaustionTest {
private HikariDataSource dataSource;
@AfterEach
void tearDown() {
if (dataSource != null) {
dataSource.close();
}
}
@Test
void requestingOneMoreConnectionThanMaximumPoolSize_failsFastWithSqlTransientConnectionException()
throws Exception {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:h2:mem:hikariexhaustion;DB_CLOSE_DELAY=-1");
config.setUsername("sa");
config.setPoolName("exhaustion-pool");
config.setMaximumPoolSize(1);
config.setConnectionTimeout(1000); // fail fast for the test, default is 30000ms
dataSource = new HikariDataSource(config);
// Hold the pool's one and only connection open.
Connection held = dataSource.getConnection();
long start = System.currentTimeMillis();
Throwable thrown = catchThrowable(() -> dataSource.getConnection());
long waitedMs = System.currentTimeMillis() - start;
System.out.println("RESULT[hikari-pool-exhaustion]: maximumPoolSize=1, connectionTimeout=1000ms | "
+ "second getConnection() waited=" + waitedMs + "ms before throwing "
+ thrown.getClass().getName() + ": " + thrown.getMessage());
assertThat(thrown).isInstanceOf(SQLTransientConnectionException.class);
assertThat(thrown.getMessage())
.as("the exception message names the pool and states it's a connection-timeout, "
+ "not a generic SQL error -- this is what to grep application logs for")
.contains("exhaustion-pool")
.contains("Connection is not available");
assertThat(waitedMs)
.as("the caller waits roughly connectionTimeout, not forever and not instantly")
.isGreaterThanOrEqualTo(900);
held.close();
// With the held connection released, a new request succeeds immediately.
try (Connection recovered = dataSource.getConnection()) {
assertThat(recovered.isValid(1)).isTrue();
}
}
private static Throwable catchThrowable(ThrowingCallable callable) {
try {
callable.call();
return null;
} catch (Throwable t) {
return t;
}
}
@FunctionalInterface
private interface ThrowingCallable {
void call() throws Exception;
}
}