Close connectons async.
Why: When db goes down, it can cause HikariCP to block on getConnection more than the allowed connectionTimeout, depending on jdbc driver timeout setting. In some cases, this could be a long time. Added a test that shows this behaviour. The test will fail w/o the changes to HikariPool.pull/147/head
parent
6131630170
commit
26bbb7cfae
@ -0,0 +1,74 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package com.zaxxer.hikari;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import com.zaxxer.hikari.mocks.MockDataSource;
|
||||
import com.zaxxer.hikari.util.PoolUtilities;
|
||||
|
||||
/**
|
||||
* Test for cases when db network connectivity goes down and close is called on existing connections. By default Hikari
|
||||
* blocks longer than getMaximumTimeout (it can hang for a lot of time depending on driver timeout settings). Closing
|
||||
* async the connections fixes this issue.
|
||||
*
|
||||
*/
|
||||
public class TestConnectionCloseBlocking {
|
||||
@Test
|
||||
public void testConnectionCloseBlocking() throws SQLException {
|
||||
HikariConfig config = new HikariConfig();
|
||||
config.setMinimumIdle(0);
|
||||
config.setMaximumPoolSize(1);
|
||||
config.setConnectionTimeout(1500);
|
||||
config.setDataSource(new CustomMockDataSource());
|
||||
|
||||
HikariDataSource ds = new HikariDataSource(config);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
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
|
||||
PoolUtilities.quietlySleep(1001);
|
||||
start = System.currentTimeMillis();
|
||||
connection = ds.getConnection(); // on physical connection close we sleep 2 seconds
|
||||
Assert.assertTrue("Waited longer than timeout",
|
||||
(PoolUtilities.elapsedTimeMs(start) < config.getConnectionTimeout()));
|
||||
} catch (SQLException e) {
|
||||
Assert.assertTrue("getConnection failed because close connection took longer than timeout",
|
||||
(PoolUtilities.elapsedTimeMs(start) < config.getConnectionTimeout()));
|
||||
} finally {
|
||||
ds.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomMockDataSource extends MockDataSource {
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
Connection mockConnection = super.getConnection();
|
||||
when(mockConnection.isValid(anyInt())).thenReturn(false);
|
||||
doAnswer(new Answer<Void>() {
|
||||
@Override
|
||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
||||
TimeUnit.SECONDS.sleep(2);
|
||||
return null;
|
||||
}
|
||||
}).when(mockConnection).close();
|
||||
return mockConnection;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue