quarkus icon indicating copy to clipboard operation
quarkus copied to clipboard

Make transactions usable with raw MongoDB client / collection interfaces

Open languitar opened this issue 3 years ago • 7 comments

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)
}

languitar avatar Aug 16 '22 11:08 languitar

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.

loicmathieu avatar Aug 16 '22 12:08 loicmathieu

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.

languitar avatar Aug 16 '22 13:08 languitar

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.

languitar avatar Aug 16 '22 13:08 languitar

/cc @evanchooly, @loicmathieu

quarkus-bot[bot] avatar Aug 22 '22 12:08 quarkus-bot[bot]

@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

loicmathieu avatar Jan 02 '23 09:01 loicmathieu

I'm looking forward to this feature.

felixng313 avatar Dec 13 '23 04:12 felixng313

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?

felixng313 avatar Feb 14 '24 02:02 felixng313