I'm using Dropwizard 1.3.12 backed with a H2 1.4.199 database. In the database config I have
database:
...
validationQuery: "/* MyService Health Check */ SELECT 1"
validationQueryTimeout: 3s
...
The problem I am running into is that the timeout of 3s also propagates to the real DB queries done in the Dropwizard application. Some DB queries are getting interrupted by this timeout. I rather have them wait a bit longer.
From my understanding validationQueryTimeout
should only control the timeout of the validationQuery
. The real DB requests done inside the application should not be affected by this. I have tried removing validationQueryTimeout
and that seems to do the trick and remove the query timeout. Doing this I see as a last resort workaround since I think it makes sense to have a timeout on the query that validates that the connection is up and running when fetching a connection from the connection pool.
I tried using Postgresql and there the validationQueryTimeout
doesn't seem to affect other DB queries.
I have done some debugging and think I found the reason, but I lack a good workaround.
When doing the validation tomcat-jdbc sets query timeout on the the validation statement. https://github.com/apache/tomcat/blob/9.0.16/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PooledConnection.java#L536-L544
stmt = connection.createStatement();
int validationQueryTimeout = poolProperties.getValidationQueryTimeout();
if (validationQueryTimeout > 0) {
stmt.setQueryTimeout(validationQueryTimeout);
}
stmt.execute(query);
stmt.close();
The big problem here is that H2 keeps the timeout on a connection level instead of a statement level. https://github.com/h2database/h2database/blob/version-1.4.199/h2/src/main/org/h2/jdbc/JdbcStatement.java#L695-L717
/**
* Sets the current query timeout in seconds.
* Changing the value will affect all statements of this connection.
* This method does not commit a transaction,
* and rolling back a transaction does not affect this setting.
*
* @param seconds the timeout in seconds - 0 means no timeout, values
* smaller 0 will throw an exception
* @throws SQLException if this object is closed
*/
@Override
public void setQueryTimeout(int seconds) throws SQLException {
try {
debugCodeCall("setQueryTimeout", seconds);
checkClosed();
if (seconds < 0) {
throw DbException.getInvalidValueException("seconds", seconds);
}
conn.setQueryTimeout(seconds);
} catch (Exception e) {
throw logAndConvert(e);
}
}
Is there something I can do? Or is a fix needed in either h2 or tomcat-jdbc? What I can think of is to get the current query timeout value in tomcat-jdbc before setting it for the validation query and then setting it back to that value after running the validation query.
You're right, it is a known limitation of H2 (see here and here)
I guess you could set the timeout to 0 to avoid the faulty behavior of H2. Then implement a JdbcInterceptor
that checks for the timeout after the statement is executed. However, it will not abort the statement when it breaches the timeout will only report afterward the exception :-(