-
-
Notifications
You must be signed in to change notification settings - Fork 83
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
Allow hooking on connection get-from-pool and release-to-pool #130
Comments
Those issues are described in the context of an async API, but r2d2 works with blocking connections. |
I think the points about "how would one handle connection errors in the Drop implementation?" (also mentionned here) are still valid in a synchronous context. Anway, that is just to justify that it isn't easy or even necessarily desirable to "just move to an RAII transaction API" that would dodge these transaction-management-on-pooled-connection-drop issues by other means. |
How would you make sure to never forget a commit call in any API? |
Well Diesel's prevents that ^^ |
I think that should be restricted to |
I am a bit confused as to how Diesel simultaneously guarantees that transactions will always be committed and needs the ability to forcibly roll back transactions when a pooled connection is returned. In any case though, it seems reasonable to add those methods to CustomizeConnection. |
I realize my previous messages may have been lacking explanation to be understandable by anyone who isn't quite familiar with diesel and its issue history ^^
It does not precisely "guarantees that transactions will always be committed", however it does provide a way for users to "make sure to never forget to make the commit call". If you were to have a guard-based transaction API, it would probably look something like this: let transaction = conn.begin_transaction()?;
query.execute(&mut transaction.connection);
transaction.commit()?; Now this has several issues:
(What I call "forget to make the commit call" is specifically "forgetting to write that last line, resulting in transaction never getting committed".) On the other hand, Diesel's API is based on a conn.transaction(|conn| {
query.execute(&mut conn);
Ok(())
})?; Notice several things:
Hence indeed, "always using the Anyway - I realize now this is irrelevant to this issue, for reasons described later.
Now there's actually two ways that this could be useful:
For that second case we have several design choices:
Notice in particular that attempting rollback only ever makes sense if the connection is pooled - otherwise it's probably fine to just let the panic unwind and drop the actual connection, which will not be reused. Diesel went with the second approach, which in particular allows users to, depending on their use-case:
Now if the user's will happens to be "I know this panic in my request handling code will be catched later, and the server will continue its life normally besides that, so I want to attempt rollback and report the error to e.g. Sentry if it fails" (spoiler: that's what we do), then the current only possible approach is
which having this would solve. Side note: I realize now that the "no-rollback-attempt on panic" behavior and "don't forget to commit" behavior are pretty untied: it's possible to obtain both "no-rollback-attempt on panic" and "rollback-attempt on panic" in both designs, by checking whether That makes the only relevant question between "no-rollback-attempt on panic" and "don't forget to commit" with regards to this issue the "no-rollback-attempt on panic" one: Not to negate of course the other uses this may have, like managing a pool of connections dedicated to tests, where we would open a transaction everytime we get it from the pool, and roll it back every time it comes back, which is very close to our original issue. |
connection checkout/in. As discussed in sfackler#130
I've opened #131 for this. |
In some cases, specific initialization/cleanup needs to be done around managed connections when fetching them from the pool and releasing them to the pool.
e.g.:
Currently this requires having custom wrappers around
PooledConnection
andPool
, which prevents from always using r2d2 directly (and requires reimplementing a whole bunch of traits on the wrappers).Something that would remove this need would be to add
on_take_from_pool
andon_release_to_pool
hooks toCustomizeConnection
(or another trait if we want backwards-compat.) and/orManageConnection
.That would solve 1. by allowing users to automatically open a test transaction
on_take_from_pool
and rolling it backon_release_to_pool
(on_release_to_pool
would have to be called beforeis_valid
).That would solve 2. by allowing users (and/or implementors of
ManageConnection
) to automatically attempt closing any open transactionson_release_to_pool
in any way they see fit.I would imagine the overhead of the
CustomizeConnection
one to be really-not-too-high despite the dynamic dispatch because that would be absolutely negligible compared with what we actually do with the connection. (And obviously the overhead of theManageConnection
one would be zero because the statically dispatched no-op would be optimized out.)Would that be something that makes sense and could potentially be added to r2d2?
Thanks,
The text was updated successfully, but these errors were encountered: