I am looking for guidance on implementation transactions when using Micronaut Data MongoDB (Reactive)
Below I have given code snippets from what I am trying to implement:
Data dependencies included:
implementation("io.micronaut.data:micronaut-data-mongodb")
implementation("io.micronaut.mongodb:micronaut-mongo-reactive")
implementation("io.micronaut.reactor:micronaut-reactor")
runtimeOnly("org.mongodb:mongodb-driver-reactivestreams")
Repository interfaces:
@MongoRepository
public interface DepartmentRepository extends ReactiveStreamsPageableRepository<Department, String> {
}
@MongoRepository
public interface OrganisationRepository extends ReactiveStreamsPageableRepository<Organisation, String> {
}
Transactional service method:
In the below method, I have added @Transactional
annotation. Within the method, I am calling two repository update
operations. To combine them, I am using zip
to subscribe for their completion and returning.
@Override
@Transactional
public Mono<Boolean> updateCounts( final MessageDto message ) {
// do something
// update department reactive
final Mono<Department> departmentUpdate = Mono.from( departmentRepository.findById( departmentId ) )
.flatMap( department -> {
// do something
return Mono.from( departmentRepository.update( department ) );
} );
log.info( "Department update mono created" );
// update organization reactive
final Mono<Organisation> organizationUpdate = Mono.from( organisationRepository.findById( orgId ) )
.flatMap( org -> {
// do something
return Mono.from( organisationRepository.update( org ) );
} );
log.info( "Org update mono created" );
// zip and respond
return Mono.zip( departmentUpdate, organizationUpdate ).map( tuple -> {
return Boolean.TRUE;
} );
Exception:
11:22:22.635 [Thread-10] WARN i.m.d.m.o.DefaultReactiveMongoRepositoryOperations - Rolling back transaction on error: Query failed with error code 251 and error message 'Given transaction number 2 does not match any in-progress transactions. The active transaction number is 1' on server localhost:27017
com.mongodb.MongoQueryException: Query failed with error code 251 and error message 'Given transaction number 2 does not match any in-progress transactions. The active transaction number is 1' on server localhost:27017
at com.mongodb.internal.operation.FindOperation$2.onResult(FindOperation.java:787)
at com.mongodb.internal.operation.CommandOperationHelper.lambda$transformingReadCallback$10(CommandOperationHelper.java:322)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor$2.onResult(DefaultServer.java:272)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
at com.mongodb.internal.connection.CommandProtocolImpl$1.onResult(CommandProtocolImpl.java:82)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection$1.onResult(DefaultConnectionPool.java:683)
at com.mongodb.internal.connection.UsageTrackingInternalConnection$2.onResult(UsageTrackingInternalConnection.java:159)
at com.mongodb.internal.async.ErrorHandlingResultCallback.onResult(ErrorHandlingResultCallback.java:48)
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:523)
at com.mongodb.internal.connection.InternalStreamConnection$2$1.onResult(InternalStreamConnection.java:498)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:821)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback$MessageCallback.onResult(InternalStreamConnection.java:785)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:642)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:250)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:233)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:129)
at java.base/sun.nio.ch.Invoker.invokeDirect(Invoker.java:160)
at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.implRead(UnixAsynchronousSocketChannelImpl.java:573)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:276)
at java.base/sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
at com.mongodb.internal.connection.AsynchronousSocketChannelStream$AsynchronousSocketChannelAdapter.read(AsynchronousSocketChannelStream.java:144)
at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:118)
at com.mongodb.internal.connection.AsynchronousChannelStream.readAsync(AsynchronousChannelStream.java:107)
at com.mongodb.internal.connection.InternalStreamConnection.readAsync(InternalStreamConnection.java:642)
at com.mongodb.internal.connection.InternalStreamConnection.access$600(InternalStreamConnection.java:86)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:775)
at com.mongodb.internal.connection.InternalStreamConnection$MessageHeaderCallback.onResult(InternalStreamConnection.java:760)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:645)
at com.mongodb.internal.connection.InternalStreamConnection$5.completed(InternalStreamConnection.java:642)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:250)
at com.mongodb.internal.connection.AsynchronousChannelStream$BasicCompletionHandler.completed(AsynchronousChannelStream.java:233)
at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:129)
at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:221)
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:113)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
at java.base/java.lang.Thread.run(Thread.java:833)
From the exception, it looks transaction is being closed at MongoDB side even though application transaction is live. It might be because ClientSession
of MongoDB is closed after the first update But I am not clear how to solve this.
I see that the below OOTB class has transaction implementation for reactive mode. So, I think transactions are supported in reactive mode as well. I am just not able to find the right way to use it.
OOTB class where I find transactional related implementation:
io.micronaut.data.mongodb.operations.DefaultReactiveMongoRepositoryOperations
Has anybody tried this and also is transaction supported in Micronaut Mongo Data Reactive Streams (Reactor Project)?