Hi,
We are encountering a connection leak detection error when using the JPA saveAll
method to persist 200 objects as a batch. The same application runs without any issues on the local machine, but it fails in the dev environment. The saveAll
method is being called from a separate thread. Please find the code snippet below for your reference.
//BATCH_QUEUE_SIZE=20
//BATCH_SIZE=200
//batchExecutor is the ThreadPoolExecutor with min core pool size is 5 and maxPoolSize is 10
int count= userReo.count();
List<CompletableFuture> batchFutures = new ArrayList<>();
long id=1;
Sort sort = Sort.by(“createdDate”).descending();
PageRequest pageRequest = PageRequest.of(pageIndex, BATCH_SIZE, sort);
for(int pageIndex=0;pageIndex<count;pageIndex++){
CompletableFuture batchFuture =
CompletableFuture.runAsync(
() → {
Slice userPage=
userRepo.findAllUsers(id, pageRequest);//returns 200 record
reEncryptUser(userPage);
},
batchExecutor)
.exceptionally(ex → {
log.info(“Error in batch pageIndex {}: {}”, finalPageIndex, ex.getMessage());
return null;
});
batchFutures.add(batchFuture);
if (batchFutures.size() >= BATCH_QUEUE_SIZE) {
CompletableFuture first = batchFutures.remove(0);
first.join(); // wait for one to finish before launching the next
}
CompletableFuture.allOf(batchFutures.toArray(new CompletableFuture[0])).join();
shutdownExecutor(); //shutdown all executor
}
reEncryptUser(userPage){
//perform some operations using different executor called it as (decryptExecutor);
//perform some operations using another executor called it as (encryptExecutor);
//iterate userpage
//set encrypted value to user
//add user in list called it as encryptedUserList
//save encryptedUserList using saveAll method.// (at this line we are getting connection leak issue)
}
Note: User object has only 6 fields
Hibernate version : 6.4.7
Hikari cp configuration:
hikari:
connectionTimeout: 30000
idle-timeout: 600000
leakDetectionThreshold: 120000 #200000
initializationFailTimeout: -1
maxLifetime: 1800000
maximumPoolSize: 25 #25
minimumIdle: 10 #10
poolName: HikariPool
connectionTestQuery: SELECT 1
housekeeping-period: 5000
stacktrace:
thread":“HikariPool housekeeper”,“logger”:“com.zaxxer.hikari.pool.ProxyLeakTask”,“message”:“Connection leak detection triggered for com.edb.jdbc.PgConnection@4234343 on thread pool-4-thread-4, stack trace follows”,“stack_trace”:“java.lang.Exception: Apparent connection leak detected\n\tat com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:127)\n\tat org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl.getConnection(DatasourceConnectionProviderImpl.java:122)\n\tat org.hibernate.internal.NonContextualJdbcConnectionAccess.obtainConnection(NonContextualJdbcConnectionAccess.java:46)\n\tat org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.acquireConnectionIfNeeded(LogicalConnectionManagedImpl.java:113)\n\tat org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getPhysicalConnection(LogicalConnectionManagedImpl.java:143)\n\tat org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.getConnectionForTransactionManagement(LogicalConnectionManagedImpl.java:273)\n\tat org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:281)\n\tat org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:232)\n\tat org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:83)\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:176)\n\tat org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:420)\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.startTransaction(AbstractPlatformTransactionManager.java:532)\n\tat org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:405)\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:604)\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:373)\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:138)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\tat org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:165)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)\n\tat jdk.proxy2/jdk.proxy2.$Proxy204.saveAll(Unknown Source)\n\tat com.org.UserMigration.reEncryptUser(UserMigration.java:577)\n\tat com.org.UserMigration.UserMigration.lambda$startReEncryption$0(UserMigration.java:165)\n\tat java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(Unknown Source)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)\n\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)\n\tat java.base/java.lang.Thread.run(Unknown Source)\n”}