quarkus
quarkus copied to clipboard
Make transactions usable with raw MongoDB client / collection interfaces
Description
The transaction support for MongoDB currently only works when using Panache entities directly. Sometimes, though, it is necessary to resort to the raw operations provided by MongoCollection etc. Such manual operations currently run outside a potentially active transaction because the session containing this transaction is not accessible for user code. The MongoDB Java driver requires to explicitly pass this session into operations for being performed inside transactions.
It would be nice if there either was a way to
- access (or newly create) a session with ongoing transaction for use with operations provided by
MongoCollection, or - to have the transaction automatically passed into the raw Java driver operations without manual actions being needed by the user code
This request is the result of https://github.com/quarkusio/quarkus/discussions/27289
Implementation ideas
From my perspective it would probably best if transaction handling based on @Transactional and other mechanisms was handled automatically by MongoClient, MongoDatabase and MongoCollection, potentially through a Quarkus-specific facade. The MongoDB driver provides for most operations two method signatures, one with a client session passed in via the first parameter, and one without that parameter. If an ongoing transaction was not handled automatically this would often result in client code like the following needed to handle the different signatures:
ClientSession session = Somewhere.getMongoDbTransaction()
if (session == null) {
res = collection.findOneAndUpdate(query, mutation)
} else {
res = collection.findOneAndUpdate(session, query, mutation)
}
potentially through a Quarkus-specific facade.
this will be a lot of work as the transactonal facade will need to be kepts in line with the underlying MongoDB 'raw' facilities.
However, two implementations could be eaisy to create:
- Panache.getMongoSession()
- Having a way to inject a request scoped objet that can obtains the session (like a specific QuarkusMongoSession on which you can call .getSession())
They may be more questions to ask so we may want to think a little more about this.
Injection sounds cleaner to me than random static methods with magic implementations that get back into the concrete context of the running request. I'm also a bit confused why QuarkusTransaction is static and not something to inject along these lines.
Not having a facade is definitely OK at the moment. It could be added later by providing other accessor methods on the repository or active record without breaking compatibility.
/cc @evanchooly, @loicmathieu
@languitar currently, the ClientSession is created lazilly at first use and registered inside the transaction manager. Then we reuse the existing transaction interceptors.
So it may be hard to provide a way to inject it as a request scoped bean.
But allowing to statically get it from an helper method (that will also create it) is not very complex so you could write someting like : Panache.getClientSession().
See this draft PR: https://github.com/quarkusio/quarkus/pull/30115
I'm looking forward to this feature.
The MongoCollection only accepts com.mongodb.client.ClientSession, but the new function Panache.getSession() is returning com.mongodb.session.ClientSession. Any advice for this case?