To simplify my problem, I have
App1 with @Transactionnal method createUser():
App2 with RabbitMQ message consumer
The problem is that sometimes, App2 tries to consume the RabbitMQ message before the transaction is even committed on App1. This means that App2 can't read the mail data on database because the user is not yet created.
Some solutions may be:
I've seen there is a RabbitTransactionManager in Spring, but I can't understand how it is supposed to work. Internals of transaction handling stuff has always seemed to be a bit hard to understand and the documentation doesn't help so much either.
Is there a way to do something like this?
How? And what to expect for example if I send synchronous RabbitMQ messages instead of asynchronous messages? Would it block the thread waiting for a response or something? Because we do send sync and async messages for different usecases.
I know this is late but I had this same problem due to my limited understanding of @Transactional at the time. So this is more for anyone else you happens to stumble upon this.
When use @Transactional to save data to the database the save to the database doesnt actually happen until the method returns, and not when the save is called.
So if you have a method like
@Transactional(readOnly=false)
public void save(Object object) { //Object should be one of your entities
entityManager.persist(object); //or however you have it set up
rabbitTemplate.convertAndSend(message); //again - however yours is
}
even tho you call the persist on the object before you put the message on the queue, the persist will not actually happen until the method returns, thus causing the message to be put on the queue before the method returns and before the data is actually in the database.
It is possible to nest @Transactional methods (tho its not straight forward) can put the message on the queue after the save()
method returns. However you cannot put the message on the queue and expect it to not be consumed. Once its there is gone. So delay putting it on the queue if you need to.
If you want to receive a response from the queue in a sync manner. In my function example - you can do this, however it will only make it take longer to actually persist the data, as it will be waiting for the response from the worker before the method can return and actually persist the data. (also remember that receiving a response from a queued message has a timeout).
So my advise is to not put those 2 operations in the same @Transactional
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With