-
Notifications
You must be signed in to change notification settings - Fork 4
Fix leaking connections when it was not possible to close them. #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
rPraml
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @rbygrave,
I've rebased this PR and thanks for merging the other PRs.
FYI: we think that the getSchema() call (introduced by me in 9.1 and removed in 9.2) was partly responsible for causing an outage in one of our production systems under the right amount of load in combination with the DB2 driver ;)
| * Possible values | ||
| * <ul> | ||
| * <li><code>nothing</code> nothing happens</li> | ||
| * <li><code>rollback</code> a rollback is performed (default)</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CHECKME: nothing was the old behaviour.
Now we do a rollback (which is recommeded by the JDBC-API) if the application code did not already rollback/commit the txn.
So in some cases, an additional command is sent to the db (=maybe slower)
Note: Ebean does the job already very well, and in 95% only committed/rollbacked connections are closed.
For example ImplicitReadOnlyTransaction does a commit at the end. See: ebean-orm/ebean@3e24190
These are the 5% left, where a transaction is put back to pool without commit/rollback. See: ebean-orm/ebean#3579
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought here is that rollback and fail are really the only options we should allow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's think again about the use cases
nothingthis would be the old behaviour. This is error prone and can result in uncommitted data not being committed until the next use. So, let’s discard the possibility of switching back to the old procedurerollbackthis option is absolutely necessary and should become the default optioncommitthis option is actually nonsense and I can't imagine a useful use caseremovealso seems to be nonsense and that there are dangling connections in the heapfailThis is for testing and it is highly recommended to enable it in unit tests. As mentioned in the comment, this should not be used in production as try-with-resources will stop working under unexpected conditions (e.g. when an exception is thrown).
We found a few places in our code where we forgot to commit the transaction and are wondering how this code could work (probably the commit was executed the next time the connection was used).
the more I think about it, I agree and think it is better to convert closeWithinTxn to a boolean enforceCleanClose or assertCleanClose, so that we have the functionality of rollback and fail.
I also would log this as a warning when we do an unexpected rollback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so that we have the functionality of rollback and fail.
Yeah, I think this sounds like the right approach at this stage.
| offline = properties.getBoolean("offline", offline); | ||
| shutdownOnJvmExit = properties.getBoolean("shutdownOnJvmExit", shutdownOnJvmExit); | ||
| validateOnHeartbeat = properties.getBoolean("validateOnHeartbeat", validateOnHeartbeat); | ||
| closeWithinTxn = properties.get("closeWithinTxn", closeWithinTxn); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately. properties does not support enums, yet. Maybe this should be changed?
ebean-datasource/src/main/java/io/ebean/datasource/pool/PooledConnection.java
Show resolved
Hide resolved
rbygrave
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy with this. Thinking we could simplify this to only allow ROLLBACK and FAIL options.
| * Possible values | ||
| * <ul> | ||
| * <li><code>nothing</code> nothing happens</li> | ||
| * <li><code>rollback</code> a rollback is performed (default)</li> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought here is that rollback and fail are really the only options we should allow.
ebean-datasource/src/main/java/io/ebean/datasource/pool/PooledConnection.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @rbygrave I've refactored this PR to support only fail/rollback.
Documentation is provided in #116
I'm unsure about the following things:
ensureCleanCloseorassertCleanCloseor do you have a better name?- what exception should be thrown, when enabled?
- SqlException? May be catched and swallowed
- IllegalStateException? May be also catched
- AssertionError? My preference (then I also should rename the property)
- Should I log the situation as warning without stack trace?
Especially the last may flood the log, but hey, these were really dangerous programming errors... (In our code, exactly that happend, that we could not explain, why data was committed without commit statement)
And as far as I can say, if you use ebean-datasource with ebean (+ this PR ebean-orm/ebean#3579) you should be safe.
ebean-datasource/src/main/java/io/ebean/datasource/pool/PooledConnection.java
Show resolved
Hide resolved
ebean-orm#107" This reverts commit e38c3e3.
DB2 has a problem, that it won't allow to close connections if there is an uncommitted UOW.
This PR adresses the following issues:
a warning is logged, that commit/rollback was missing. We also try to roll back this connection, as in the worst case, data can leak to the next usage.
This is done here: https://github.com/ebean-orm/ebean-datasource/compare/master...FOCONIS:ebean-datasource:db2-tests?expand=1#diff-916f1a5da1ef6f478d7cb23223fc9bfd2fb0c64ff6b0484f399c19403c6ddb8fR457
When shutting down the pool, we always try to roll back the connection first, before it will be closed. If this is not done, DB2 will not close the transaction, if there is still UOW open. This can happen, as various commands like
getSchemacan start a new UOW an already committed/rollbacked connection. The connection will be never closed and the tcp/ip connection kept open until the JVM will restartSee test
testFalseFriendRollbackWe changed the invocation of
DataSourcePoolListener.onBeforeReturnConnectionto the beginning of the whole reset process of autocommit/isolationLevel/catalog/schema/status=IDLE.This allows us to install a custom DB2-listener. While 1 + 2 will cover 95% of leaking connections, the listener can check
isInDB2UnitOfWorkand handle the other 5%.This might be considered as behaviour change, if you think,
onBeforeReturnConnectionshould be the last method, I can add aonBeforeResetConnectionto the listener.I know, the behaviour of DB2-JCC driver is a bit odd here (and could theoretically be configured with
connectionCloseWithInFlightTransactionparameter) - but it is as it is. And we had major outages last week.@rbygrave It would be great, if we get feedback about these changes
/edit: What happened exactly:
This change 94f9f71#diff-916f1a5da1ef6f478d7cb23223fc9bfd2fb0c64ff6b0484f399c19403c6ddb8fR125 caused the trouble.
The change to
getSchema()in the initialization (which is already removed in 9.2) makes this scenario more likely.So now, we have either improved the close logic (to try a rollback) and also do a rollback in the heartbeat
https://github.com/ebean-orm/ebean-datasource/pull/107/files#diff-17a97b637b84f5d3e16f487dcd4a8d80d7cdb9f165b528cdc4d495cc93070647R380
Note: The JDBC-documentation says https://docs.oracle.com/javase/8/docs/api/java/sql/Connection.html#close--
So I think, we can enforce this behaviour. I also think we may throw an exception instead of the Log.trace