1

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

  • Which version of Micronaut Data do you use? It looks like a bug. Can you please create an issue? – Denis Mar 01 '23 at 14:15
  • Hi @Denis, Thanks for your response. I have now tried with both versions 3.8.1 and 3.9.6 (latest). I see same issue in both versions. I have raised an issue here: [2048](https://github.com/micronaut-projects/micronaut-data/issues/2048) – Satheesh Kumar Ramasamy Mar 02 '23 at 09:06
  • https://guides.micronaut.io/latest/micronaut-data-mongodb-asynchronous-gradle-java.html The guide says Transaction mode is not supported when the synchronous transaction manager is created using Reactive transaction manager! – Siddhivinayak May 08 '23 at 13:29

0 Answers0