Affects: \Spring 5.3


OpenEntityManagerInViewFilter closes the EntityManager when processing synchronous requests and appears to defer to AsyncRequestInterceptor to handle the closing of the EntityManager for Async requests.

The issue is that AsyncRequestInterceptor will only close the EntityManager when a timeout or error occurs:

private void closeSession() {
        if (this.timeoutInProgress || this.errorInProgress) {
            logger.debug("Closing Hibernate Session after async request timeout/error");
            SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
        }
}

This was resulting in leaked HikariCP connections in my application for my REST Controller that returns a StreamingResponseBody, to stream data from a JPA connection.

To resolve this, I created a modified copy of AsyncRequestInterceptor where I made the session closing unconditional:

private void closeSession() {
    logger.debug("Closing Hibernate Session after async request");
    SessionFactoryUtils.closeSession(this.sessionHolder.getSession());
}

I then use this modified AsyncRequestInterceptor class by using a modified copy of OpenEntityManagerInViewFilter that invokes my version of AsyncRequestInterceptor instead of the standard version shipped with Spring.

Comment From: rstoyanchev

The full lifecycle of an asynchronous request involves an initial REQUEST dispatch during which the controller decides to handle the request asynchronously. On the way out, OpenEntityManagerInViewFilter will not close EntityManager because isAsyncStarted returns true and the request is not yet fully handled. Then your StreamingResponseBody will write to the response on a Spring MVC managed thread, and when that's done, it performs an additional ASYNC dispatch for final handling of the result, and that should pass through the filter one more time, and on the way out isAsyncStarted should then be false, and the connection should be closed.

AsyncRequestInterceptor on the other hand, is there to handle timeout and error cases, that would interrupt the usual flow. So this is all by design, and it's not yet clear why you're seeing leaked connections.

Perhaps you can debug a little further to confirm that on a typical request, it works as described above. If not, then we need to find out in more detail why it doesn't. If it works as expected for the normal case, then you might need to investigate further to see under what conditions connections specifically are leaked.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.