-
Notifications
You must be signed in to change notification settings - Fork 36
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
No rollback if thread ends during transaction; poisoned handles end up in connection pool #76
Comments
Doing a little more research on the feasibility of improving the plugin by reading the state from DBI, I think I've hit a brick wall. Apparently there is a Given the uncertain nature of relying on a documented feature, one option might be for the plugin to intercept the begin_work(), rollback(), and commit() methods, and definitively implement the begunwork option above within the plugin. Then when a dbh is returned to the pool, $dbh->rollback() if $dbh->{begunwork}, prior to assigning the handle to a new thread. |
Sorry for the lack of response here. I had a think, but hit a mental brick wall and had an oh look a squirrel moment. Yeah, you're quite probably right that catching begin_work(), rollback() etc calls and keeping state there could work. However - there isn't really a concept of returning handles to a pool to give to another thread - it's one handle per process/thread, and therefore it's the same handle that that same process gets later. The problem comes with what happens if you say e.g.:
... rather than grabbing the handle and storing it yourself briefly. Each of those calls fetches the same handle, but how can the plugin know if you're expecting it to have uncommitted changes or not? I suspect a suitable solution may be for the plugin to add an |
I use the following configuration:
The above is defined globally as described here:
#75
For single-statement write transactions I just rely on
AutoCommit=1
andRaiseError=1
to automatically commit each transaction and to automatically raise any errors.This works very well. If there's a problem, the app dies and the error is reported nicely by Dancer. No need to clutter up the code with
... or die $dbh->errstr
everywhere.The problem occurs with transactions. The pattern I use is:
If there's a problem with any of the SQL writes within the transaction block, or some other exception gets thrown within the transaction, the database handle (with the uncommitted, unrolledback transactions) gets returned back to the connections pool within the plugin. That handle then eventually gets picked up by another thread later, and all sorts of really bad things happen.
It seems to me the plugin should somehow check the database handle when it's returned to the pool, and if it contains a pending transaction,
$dbh->rollback();
should be invoked.Note that just detecting
die
at end of thread execution would not be enough, because it wouldn't prevent a sloppy coder from poisoning the connection pool like this:I'm not sure if this is in the category of "bug/issue", or "wishlist", but it seems to me it's the former because the plug-in is allowing bad handles back into the pool.
Workaround: To get around this issue, I started using the following pattern which so far appears to work:
I'm not thrilled about repeating the above code, over and over again, throughout my app. I'm lazy and sloppy.
I'm very open to suggestions/improvements on the above workaround.
The text was updated successfully, but these errors were encountered: