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.