Skip to content
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

Application event listeners do not participate in reactive transactions [DATAMONGO-2632] #3487

Closed
spring-projects-issues opened this issue Sep 24, 2020 · 2 comments
Assignees
Labels
status: duplicate A duplicate of another issue type: bug A general bug

Comments

@spring-projects-issues
Copy link

Jose Antonio Iñigo opened DATAMONGO-2632 and commented

Base scenario:

  • Spring Boot 2.3.4 Webflux application
  • Reactive MongoDB with ReactiveMongoTransactionManager for multidocument transactionality

 

@EnableTransactionManagement
@Configuration
class MongoDbConfiguration {

    @Bean
    fun mongoTransactionManager(dbFactory: ReactiveMongoDatabaseFactory) =
            ReactiveMongoTransactionManager(dbFactory)

}

 

The controller is called to create a user :

@PostMapping
fun create(@RequestBody user: UserCreate) = userService.create(User(null, user.name))

 

UserServiceImpl.create is a transactional method that saves the user and publishes a UserCreatedEvent:

@Service
@Transactional
class UserServiceImpl(private val userRepository: UserRepository,
                      private val applicationEventPublisher: ApplicationEventPublisher) : UserService {

    private val logger = LoggerFactory.getLogger(javaClass)

    override fun create(user: User): Mono<User> {
        logger.info("create() isSyncActive {} - isTxActive {}",
                TransactionSynchronizationManager.isSynchronizationActive(),
                TransactionSynchronizationManager.isActualTransactionActive())
        return userRepository.save(user)
                .flatMap {
                    applicationEventPublisher.publishEvent(UserCreatedEvent(it))
                    it.toMono()
                }
    }

Finally BillingServiceImpl.userCreated is an event listener that checks that the user exists and in this case creates a Billing asociated to that user:

@Service
class BillingServiceImpl(private val userRepository: UserRepository,
                         private val billingRepository: BillingRepository) {

    private val logger = LoggerFactory.getLogger(javaClass)

    @EventListener
    @Transactional
    fun userCreated(event: UserCreatedEvent): Mono<Billing> {
        logger.info("userCreated({})", event)
        return userRepository.findById(event.user.id!!)
                .switchIfEmpty {
                    UserDoesntExistException(event.user.id!!).toMono()
                }.flatMap {
                    logger.info("*** CREATING BILLING for user {}", it)
                    billingRepository.save(Billing(null, event.user.id!!))
                }
    }

There are the two problems I've found:

  • Most times UserDoesntExistException is launched, even though in the logs we can see (Inserting Document containing fields: [name, _class] in collection: sample-user). Given that the EventListener method failed I assumed the global transaction would be rolled back. However the user is created and stored without rolling back.
  • Some times the exception is not launched and the Billing is correctly saved. This should be what happened always. Why can't it always see the user created in the same transaction??

I've reference a sample project. You need a MongoDB instance with replication (to support multidocument transactions, e.g.: MongoDb Atlas). Just configure the spring.data.mongodb.uri property form application.yml inside the project.

To call the controller: curl -X POST localhost:8080/users -d '{"name": "John Doe"}' -H "content-type: application/json"


Affects: 3.0.4 (Neumann SR4)

Reference URL: https://github.com/codependent/transactional-event-sample/tree/event-listener

@spring-projects-issues
Copy link
Author

Mark Paluch commented

Please do not cross-post. Closing since this is a cross-post of spring-projects/spring-framework#25805

@spring-projects-issues
Copy link
Author

Jose Antonio Iñigo commented

Mark Paluch Sorry, today I read in Spring Data's Github repo that issues for Spring Data had to be opened in Jira and though that this is where it belonged. I'll wait for updates in Github then. Regards!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants