micronaut-data icon indicating copy to clipboard operation
micronaut-data copied to clipboard

@Async function closes Entity Manager prematurely

Open bleonard-tl opened this issue 2 years ago • 9 comments

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

  1. Run the application server from the linked, it is a very slimmed down version of my full application
  2. 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"
}
  1. Take note of the jobId of the response
  2. 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}}"
}
  1. 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

bleonard-tl avatar Aug 09 '23 19:08 bleonard-tl

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

Argannor avatar Aug 10 '23 12:08 Argannor

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)

dstepanov avatar Aug 10 '23 13:08 dstepanov

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.

Argannor avatar Aug 10 '23 14:08 Argannor

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!

bleonard-tl avatar Aug 10 '23 14:08 bleonard-tl

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 avatar Aug 10 '23 14:08 dstepanov

@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.

harshSE avatar Aug 17 '23 18:08 harshSE

Please create an example project for me to take a look

dstepanov avatar Aug 17 '23 18:08 dstepanov

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:

  1. Run the Application using ./gradlew run
  2. Make a post request to http://localhost/book with 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.

harshSE avatar Aug 17 '23 21:08 harshSE

Same problem. Workaround:

 @Transactional(propagation = TransactionDefinition.Propagation.REQUIRES_NEW)
  @EventListener
  public void exceptionOnEvent(NewBookCreatedEvent newBookCreatedEvent) {

dstepanov avatar Aug 19 '23 07:08 dstepanov