Skip to content

Commit 36f59e1

Browse files
authored
Merge pull request #96 from ebean-orm/feature/heartBeat-1
Add validateOnHeartbeat with the ability to turn this off (typically for use with Lambda)
2 parents f32f897 + 2833b4f commit 36f59e1

File tree

7 files changed

+88
-7
lines changed

7 files changed

+88
-7
lines changed

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceBuilder.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,15 @@ default DataSourceBuilder initDatabaseForPlatform(String platform) {
696696
*/
697697
DataSourceBuilder shutdownOnJvmExit(boolean shutdownOnJvmExit);
698698

699+
/**
700+
* Set whether the connection pool should be validated periodically.
701+
* <p>
702+
* This is enabled by default. Generally we only want to turn this
703+
* off when using the pool with a Lambda function.
704+
* @param validateOnHeartbeat Use false to disable heartbeat validation.
705+
*/
706+
DataSourceBuilder validateOnHeartbeat(boolean validateOnHeartbeat);
707+
699708
/**
700709
* EXPERIMENTAL feature - Set to true when using in Lambda to enable an extra
701710
* check to detect when the function has been restored from suspension.
@@ -753,6 +762,11 @@ interface Settings extends DataSourceBuilder {
753762
*/
754763
boolean isShutdownOnJvmExit();
755764

765+
/**
766+
* When true validate the pool when the heartbeat runs.
767+
*/
768+
boolean isValidateOnHeartbeat();
769+
756770
/**
757771
* Return the connection properties including credentials and custom parameters.
758772
*/

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceConfig.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ public class DataSourceConfig implements DataSourceBuilder.Settings {
8181
private String applicationName;
8282
private boolean shutdownOnJvmExit;
8383
private boolean useLambdaCheck;
84+
private boolean validateOnHeartbeat = true;
8485

8586
@Override
8687
public Settings settings() {
@@ -146,7 +147,7 @@ public DataSourceConfig copy() {
146147

147148
@Override
148149
public DataSourceConfig setDefaults(DataSourceBuilder builder) {
149-
DataSourceBuilder.Settings other = builder.settings();
150+
Settings other = builder.settings();
150151
if (driver == null) {
151152
driver = other.driver();
152153
}
@@ -704,6 +705,17 @@ public DataSourceConfig shutdownOnJvmExit(boolean shutdownOnJvmExit) {
704705
return this;
705706
}
706707

708+
@Override
709+
public boolean isValidateOnHeartbeat() {
710+
return validateOnHeartbeat;
711+
}
712+
713+
@Override
714+
public DataSourceConfig validateOnHeartbeat(boolean validateOnHeartbeat) {
715+
this.validateOnHeartbeat = validateOnHeartbeat;
716+
return this;
717+
}
718+
707719
@Override
708720
public DataSourceBuilder useLambdaCheck(boolean useLambda) {
709721
this.useLambdaCheck = useLambda;
@@ -768,6 +780,7 @@ private void loadSettings(ConfigPropertiesHelper properties) {
768780
poolListener = properties.get("poolListener", poolListener);
769781
offline = properties.getBoolean("offline", offline);
770782
shutdownOnJvmExit = properties.getBoolean("shutdownOnJvmExit", shutdownOnJvmExit);
783+
validateOnHeartbeat = properties.getBoolean("validateOnHeartbeat", validateOnHeartbeat);
771784
useLambdaCheck = properties.getBoolean("useLambdaCheck", useLambdaCheck);
772785

773786
String isoLevel = properties.get("isolationLevel", _isolationLevel(isolationLevel));

ebean-datasource-api/src/test/java/io/ebean/datasource/DataSourceConfigTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public void loadSettings() throws IOException {
170170
var config = new DataSourceConfig().loadSettings(props, "foo");
171171
assertConfigValues(config);
172172
assertThat(config.isShutdownOnJvmExit()).isTrue();
173+
assertThat(config.isValidateOnHeartbeat()).isTrue();
173174
assertThat(config.useLambdaCheck()).isTrue();
174175
}
175176

@@ -182,6 +183,7 @@ public void load_prefix() throws IOException {
182183
assertConfigValues(config);
183184
assertThat(config.isShutdownOnJvmExit()).isFalse();
184185
assertThat(config.useLambdaCheck()).isFalse();
186+
assertThat(config.useLambdaCheck()).isFalse();
185187
}
186188

187189
@Test

ebean-datasource-api/src/test/resources/example.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ datasource.foo.applicationName=myApp
77
datasource.foo.clientInfo=ClientUser=ciu;ClientHostname=cih
88
datasource.foo.shutdownOnJvmExit=true
99
datasource.foo.useLambdaCheck=true
10+
datasource.foo.validateOnHeartbeat=true

ebean-datasource/src/main/java/io/ebean/datasource/pool/ConnectionPool.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ final class ConnectionPool implements DataSourcePool {
4242
private final List<String> initSql;
4343
private final String user;
4444
private final String schema;
45-
private final String heartbeatsql;
45+
private final String heartbeatSql;
4646
private final int heartbeatFreqSecs;
4747
private final int heartbeatTimeoutSeconds;
4848
private final long trimPoolFreqMillis;
@@ -62,6 +62,7 @@ final class ConnectionPool implements DataSourcePool {
6262
private final String applicationName;
6363
private final DataSource source;
6464
private final int lambdaTrimMillis;
65+
private final boolean validateOnHeartbeat;
6566
private long nextTrimTime;
6667
private long nextLambdaTrimTime;
6768

@@ -111,10 +112,11 @@ final class ConnectionPool implements DataSourcePool {
111112
this.pstmtCacheSize = params.getPstmtCacheSize();
112113
this.minConnections = params.getMinConnections();
113114
this.maxConnections = params.getMaxConnections();
114-
this.heartbeatsql = params.getHeartbeatSql();
115115
this.waitTimeoutMillis = params.getWaitTimeoutMillis();
116116
this.heartbeatFreqSecs = params.getHeartbeatFreqSecs();
117117
this.heartbeatTimeoutSeconds = params.getHeartbeatTimeoutSeconds();
118+
this.heartbeatSql = params.getHeartbeatSql();
119+
this.validateOnHeartbeat = params.isValidateOnHeartbeat();
118120
this.trimPoolFreqMillis = 1000L * params.getTrimPoolFreqSecs();
119121
this.applicationName = params.getApplicationName();
120122
this.clientInfo = params.getClientInfo();
@@ -374,7 +376,9 @@ private void trimIdleConnections() {
374376
*/
375377
private void heartBeat() {
376378
trimIdleConnections();
377-
testConnection();
379+
if (validateOnHeartbeat) {
380+
testConnection();
381+
}
378382
}
379383

380384
private void testConnection() {
@@ -501,15 +505,15 @@ long maxAgeMillis() {
501505
}
502506

503507
private boolean testConnection(Connection conn) throws SQLException {
504-
if (heartbeatsql == null) {
508+
if (heartbeatSql == null) {
505509
return conn.isValid(heartbeatTimeoutSeconds);
506510
}
507511
// It should only error IF the DataSource is down or a network issue
508512
try (Statement stmt = conn.createStatement()) {
509513
if (heartbeatTimeoutSeconds > 0) {
510514
stmt.setQueryTimeout(heartbeatTimeoutSeconds);
511515
}
512-
stmt.execute(heartbeatsql);
516+
stmt.execute(heartbeatSql);
513517
return true;
514518
} finally {
515519
if (!conn.getAutoCommit()) {

ebean-datasource/src/main/java/io/ebean/datasource/pool/PooledConnectionQueue.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ void returnPooledConnection(PooledConnection c, boolean forceClose) {
174174
}
175175
if (forceClose || c.shouldTrimOnReturn(lastResetTime, maxAgeMillis)) {
176176
c.closeConnectionFully(false);
177-
178177
} else {
179178
freeList.add(c);
180179
notEmpty.signal();

ebean-datasource/src/test/java/io/ebean/datasource/test/FactoryTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,54 @@ void readOnly() throws Exception {
5353
pool.shutdown();
5454
}
5555

56+
// @Disabled
57+
@Test
58+
void heartbeatTrimOnly() throws Exception {
59+
DataSourcePool pool = DataSourcePool.builder()
60+
.name("heartbeatTrimOnly")
61+
.url("jdbc:h2:mem:heartbeatTrimOnly")
62+
.username("sa")
63+
.password("")
64+
.readOnly(true)
65+
.autoCommit(true)
66+
.validateOnHeartbeat(false)
67+
.heartbeatFreqSecs(1)
68+
.trimPoolFreqSecs(1)
69+
.maxInactiveTimeSecs(3)
70+
.build();
71+
72+
try (Connection connection = pool.getConnection()) {
73+
try (PreparedStatement stmt = connection.prepareStatement("create table junk4 (acol varchar(10))")) {
74+
stmt.execute();
75+
connection.commit();
76+
}
77+
}
78+
List<Connection> connections = new ArrayList<>();
79+
for (int i = 0; i < 10; i++) {
80+
connections.add(pool.getConnection());
81+
}
82+
for (Connection connection : connections) {
83+
connection.close();
84+
}
85+
Thread.sleep(1000);
86+
List<Connection> connections2 = new ArrayList<>();
87+
for (int i = 0; i < 4; i++) {
88+
Connection c = pool.getConnection();
89+
connections2.add(c);
90+
}
91+
for (Connection connection : connections2) {
92+
try (PreparedStatement ps = connection.prepareStatement("select * from junk4")) {
93+
ps.execute();
94+
}
95+
connection.close();
96+
}
97+
for (int i = 0; i < 5; i++) {
98+
Thread.sleep(1000);
99+
System.out.println(".");
100+
}
101+
pool.shutdown();
102+
}
103+
56104
@Disabled
57105
@Test
58106
void readOnly2() throws Exception {

0 commit comments

Comments
 (0)