micronaut-data
micronaut-data copied to clipboard
@Async function closes Entity Manager prematurely
Expected Behavior
The database calls should be able to continue to use the same entity manager / session until the end of asynchronous execution.
Actual Behaviour
Asynchronous thread errors with Session/EntityManager is closed message. Removing the @Async annotation prevents the error from happening and I could not find anything that would seem to close the connection early. This function worked without problems in a 3.5.3 Micronaut application but when upgrading to 4.0.2, it broke.
Steps To Reproduce
- Run the application server from the linked, it is a very slimmed down version of my full application
- Make an POST request to http://localhost:8090/api/jobs with the following sample payload to create a "job"
{
"configuration": "[configuration test]" ,
"publisherIds": [{"publisherId":1,"cueIds":[1,2]},{"publisherId":2,"cueIds":[3,4]}],
"createdBy": "bleonard",
"comment": "comment test",
"demandSource": "MANUAL"
}
- Take note of the
jobIdof the response - Make an POST request to http://localhost:8090/api/jobs/initiations with the following sample payload to start the "job" filling in the
jobId
{
"jobId": "{{previous_jobId_value_here}}"
}
- Find that the request completed successfully but the asynchronous execution fails with the aforementioned error
Environment Information
- Operating System: MacOS Ventura 13.5
- JDK 17
Example Application
https://github.com/bleonard-tl/micronaut-async-problem-reproduction
Version
4.0.2
Thank you for opening this issue, I encountered it too and was about to create an issue myself. I already created a minimal project for reproducing the issue containing two branches (main with Micronaut 4, and micronaut-3 with Micronaut 3.10) showing the regression: https://github.com/Argannor/micronaut-session-closed
New context propagation is propagating the TX context to the new async-thread, which will fail because the session will close.
The solution is to use @Transactional(Transactional.TxType.REQUIRES_NEW)
I see, it also works when the method firing the event is not running within a transaction. The fix with REQUIRES_NEW works.
Sadly I couldn't find that mentioned in the changelog as a breaking change, only that the transaction and connection management was redone.
I can confirm that @dstepanov's suggestion works as well! Can you help me understand a bit more? Originally the problem came up where it was working fine pre-4.0 upgrade for my project and that confuses me a little.
Are you saying that context propagation logic changed and that anytime we chain async threads we should expect to force a new transaction from now forward? Either way glad that the problem is gone!
It used to work because the context wasn’t propagated so a new TX was created anyway, now it tries to continue the TX. I will try to come up with a solution to avoid this kind of propagation
@dstepanov, we are encountering a similar issue. However, we have refrained from making the EventListener async. Instead, we are utilizing the publishEventAsync API from ApplicationEventPublisher to disseminate events.
Please create an example project for me to take a look
Please create an example project for me to take a look
@dstepanov, I have created a sample project which reproduces this issue: micronaut-data-async-session-closed-problem
Step to Reproduce:
- Run the Application using
./gradlew run - Make a post request to
http://localhost/bookwith payload to create a book
{
"id": null,
"name": "name",
"isbn": "isbn"
}
OR
You can run the ./gradlew test command which runs MicronautTest, and send a post request to reproduce the issue.
Same problem. Workaround:
@Transactional(propagation = TransactionDefinition.Propagation.REQUIRES_NEW)
@EventListener
public void exceptionOnEvent(NewBookCreatedEvent newBookCreatedEvent) {