HikariCP Idle connections staying in connection pool as active - spring

I am using Spring Boot (1.5.6), Hibernate, Postgres, Hikari (2.7.8) . My configuration is :
spring.datasource.hikari.minimumIdle=1
spring.datasource.hikari.maximumPoolSize=20
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.poolName=SpringBootJPAHikariCP
spring.datasource.hikari.maxLifetime=50000
spring.datasource.hikari.connectionTimeout=30000
What I expect is, Idle connections should be released after 30000 ms/ 30 sec of idleness.
The problem is with every request new connection being made leaving all the idle connection as it is. So after some times I end up with 20 idle connection and with a new request Hikari try to gain a new connection and get SpringBootJPAHikariCP - Connection is not available, request timed out after 30001ms.
So, What I am doing wrong.? Or Have the misunderstood the configuration?
Hikari initialization Log:
SpringBootJPAHikariCP - configuration:
allowPoolSuspension.............false
autoCommit......................true
catalog.........................none
connectionInitSql...............none
connectionTestQuery.............none
connectionTimeout...............30000
dataSource......................none
dataSourceClassName.............none
dataSourceJNDI..................none
dataSourceProperties............{password=<masked>}
driverClassName................."org.postgresql.Driver"
healthCheckProperties...........{}
healthCheckRegistry.............none
idleTimeout.....................30000
initializationFailFast..........true
initializationFailTimeout.......1
isolateInternalQueries..........false
jdbc4ConnectionTest.............false
jdbcUrl.........................jdbc:postgresql://localhost:5432/dbname
leakDetectionThreshold..........0
maxLifetime.....................50000
maximumPoolSize.................20
metricRegistry..................none
metricsTrackerFactory...........none
minimumIdle.....................1
password........................<masked>
poolName........................"SpringBootJPAHikariCP"
readOnly........................false
registerMbeans..................false
scheduledExecutor...............none
scheduledExecutorService........internal
schema..........................none
threadFactory...................internal
transactionIsolation............default
username........................"postgres"
validationTimeout...............5000
Update:
In last 24 hour I have tried several solution from different thread and none of them fixed my issue. So here is the observations that might be important.
SpringBootJPAHikariCP - Reset (autoCommit) on connection org.postgresql.jdbc.PgConnection#1344bbf1 found this log. studied
Reset (autoCommit) on connection in HikariCP this thread. tried to set auto commit same (true) at both side (hibernate and Hikari) and tried with false at both side also. still no luck.
Enables leakDetectionThreshold, got leak detection exception. So tried to understand if hibernate/spring transaction manager releasing connections. From bellow Logs it looks like hibernate working fine.
28 22:19:35- DEBUG - o.s.orm.jpa.JpaTransactionManager-371 :: Opened new EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#4212be39] for JPA transaction
28 22:19:35- DEBUG - o.h.e.t.internal.TransactionImpl-51 :: begin
28 22:19:35- DEBUG - o.s.orm.jpa.JpaTransactionManager-403 :: Exposing JPA transaction as JDBC transaction [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#243e942]
2com.someentity.MyEntity#ac918eed-345f-4a6c-8539-fe14e7fc41e2
28 22:19:35- DEBUG - o.h.r.j.i.LogicalConnectionManagedImpl-137 :: Initiating JDBC connection release from afterTransaction
28 22:19:35- DEBUG - c.zaxxer.hikari.pool.ProxyConnection-242 :: SpringBootJPAHikariCP - Executed rollback on connection org.postgresql.jdbc.PgConnection#1344bbf1 due to dirty commit state on close().
28 22:19:35- DEBUG - o.h.e.i.AbstractFlushingEventListener-132 :: Processing flush-time cascades
28 22:19:35- DEBUG - o.h.e.i.AbstractFlushingEventListener-174 :: Dirty checking collections
28 22:19:35- DEBUG - org.hibernate.internal.SessionImpl-508 :: Disconnecting session
28 22:19:35- DEBUG - o.s.orm.jpa.JpaTransactionManager-759 :: Initiating transaction commit
28 22:19:35- DEBUG - o.s.orm.jpa.JpaTransactionManager-512 :: Committing JPA transaction on EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#4212be39]
28 22:19:35- DEBUG - o.h.e.t.internal.TransactionImpl-62 :: committing
28 22:19:35- DEBUG - o.h.r.j.i.LogicalConnectionManagedImpl-137 :: Initiating JDBC connection release from afterTransaction
28 22:19:35- DEBUG - o.h.r.j.i.LogicalConnectionManagedImpl-137 :: Initiating JDBC connection release from afterTransaction
28 22:19:35- DEBUG - o.s.orm.jpa.JpaTransactionManager-600 :: Closing JPA EntityManager [org.hibernate.jpa.internal.EntityManagerImpl#4212be39] after transaction
28 22:19:35- DEBUG - o.s.o.jpa.EntityManagerFactoryUtils-435 :: Closing JPA EntityManager
All the idle connectiona are idle form postgres point of view and active form Hikari point of view. So when there are 5 idle connection from database, there are toatal = 5, active=4, idle = ,waiting=0 in Hikari log.
Note:
may be I am having this exact issue https://github.com/brettwooldridge/HikariCP/issues/109 in my case active connection increasing with every transaction.
HikariCP - connection is not available this is also a same issue. but nobody provide clear solution to this. btw I was using #Transactional from the begging as suggested by the accepted answer.

This was not any Hikari issue, there was a mistake in my end. Still posting the details of how this occurred, in case it helps someone.
I was using spring boot 1.5.6 (This was the latest version when I start working).
This version included spring-orm 4.3.1. This version of spring-orm included support for three versions of hibernate, Hibernate5, Hibernate4 and Hibernate3.
So I configured spring boot with bellow configuration for current_session_context_class.
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
Everything was working fine until it comes to connection management of Hikari. What happened is spring-boot-starter-jpa for 1.5.6 included Hibernate5 (I mean hibernate core) .
So, After performing any DB operation spring loosing control of that connection (most possibility for this version mismatch). Hence the problem.
After changing
org.springframework.orm.hibernate4.SpringSessionContext
to
org.springframework.orm.hibernate5.SpringSessionContext
the problem was solved immediately.
My current configuration is
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
FYI, after solving the problem is switched to Spring Boot 2.

Related

Spring Boot tests accessing Hikari datasource via JNDI causing connection leak?

Our SpringBoot tests use Hikari datasource obtained via JNDI.
So from test to test the embedded server is started/shutdown.
Since HikariPool start printed in the log, but none of shutdown, does it mean that our tests are causing connection leak ?
Found these:
INFO HikariDataSource - HikariPool - Starting...
INFO HikariDataSource - HikariPool - Start completed.
But none of these:
INFO HikariDataSource - HikariPool - Shutdown initiated...
INFO HikariDataSource - HikariPool - Shutdown completed.
Should I worry about it?
Any advice would be greatly appreciated.
Best regards,
SetNug

Spring #Transactional on suspend function

I am kind of frustrated right now as I thought this will be much easier and the issue would be documented way better but I just can not find a solution. Therefore I seek help here.
I am working on a Kotlin project which leverages spring boot version 2.5.3 and uses spring data jpa for database access and schema definition. Pretty common and straight-forward. Now assume we have some kind of UserService which contains a method updateUsername which gets a username as a parameter und updates the username after it verified its validity by an external service. For demo purposes of the issue I want to highlight, before we verify the username we set the username manually to "foo". This whole unit of work should happend in a transaction which is why the method is annotated with #Transactional. But because of the call to the external service the method will suspend when we wait for the http response (note the suspend keyword on both methods).
#Service
class UserService(private val userRepository: UserRepository) {
#Transactional
suspend fun setUsername(id: UUID, username: String): Person {
logger.info { "Updating username..." }
val user = userRepository.findByIdentityId(identityId = id)
?: throw IllegalArgumentException("User does not exist!")
// we update the username here but the change will be overridden after the verification to the actual username!
user.userName = "foo"
verifyUsername(username)
user.userName = username
return userRepository.save(user)
}
private suspend fun verifyUsername(username: String) {
// assume we are doing some kind of network call here which will suspend while waiting got a response
logger.info { "Verifying..." }
delay(1000)
logger.info { "Finished verifying!" }
}
}
This compiles successfully and I can also execute the method and it starts a new transaction, but the transaction will be commited as soon as we suspend the invocation of the verifyUsername method on calling delay(1000). Therefore our database will acually hold the value "foo" as the username until it is overwritten. But if the code after verifyUsername would fail and throw an exception, we could not rollback this change as the transaction was already commited and foo would stay in the database forever!!! This is definitely not the expected behavior as we only want to commit the transaction at the very end of our method, so we can rollback the transaction at any time if something went wrong. Here you can see the logs:
DEBUG o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name [x.x.x.UserService.setUsername]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG o.s.orm.jpa.JpaTransactionManager - Opened new EntityManager [SessionImpl(1406394125<open>)] for JPA transaction
DEBUG o.s.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#9ec4d42]
INFO x.x.x.UserService - Updating username...
DEBUG org.hibernate.SQL - select person0_.id as id1_6_, person0_.email as email2_6_, person0_.family_name as family_n3_6_, person0_.given_name as given_na4_6_, person0_.identity_id as identity5_6_, person0_.user_name as user_nam6_6_ from person person0_ where person0_.identity_id=?
INFO x.x.x.UserService - Verifying...
DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [SessionImpl(1406394125<open>)]
DEBUG org.hibernate.SQL - update person set email=?, family_name=?, given_name=?, identity_id=?, user_name=? where id=?
DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(1406394125<open>)] after transaction
INFO x.x.x.UserService - Finished verifying
DEBUG o.s.orm.jpa.JpaTransactionManager - Creating new transaction with name [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
DEBUG o.s.orm.jpa.JpaTransactionManager - Opened new EntityManager [SessionImpl(319912425<open>)] for JPA transaction
DEBUG o.s.orm.jpa.JpaTransactionManager - Exposing JPA transaction as JDBC [org.springframework.orm.jpa.vendor.HibernateJpaDialect$HibernateConnectionHandle#1dd261da]
DEBUG org.hibernate.SQL - select person0_.id as id1_6_0_, person0_.email as email2_6_0_, person0_.family_name as family_n3_6_0_, person0_.given_name as given_na4_6_0_, person0_.identity_id as identity5_6_0_, person0_.user_name as user_nam6_6_0_ from person person0_ where person0_.id=?
DEBUG o.s.orm.jpa.JpaTransactionManager - Initiating transaction commit
DEBUG o.s.orm.jpa.JpaTransactionManager - Committing JPA transaction on EntityManager [SessionImpl(319912425<open>)]
DEBUG org.hibernate.SQL - update person set email=?, family_name=?, given_name=?, identity_id=?, user_name=? where id=?
DEBUG o.s.orm.jpa.JpaTransactionManager - Closing JPA EntityManager [SessionImpl(319912425<open>)] after transaction
In this spring article it says that "Transactions on Coroutines are supported via the programmatic variant of the Reactive transaction management provided as of Spring Framework 5.2. For suspending functions, a TransactionalOperator.executeAndAwait extension is provided."
Does that mean that #Transactional just cannot be used on suspending methods and you should programatically handle transaction management? Update: This thread states that #Transactional should work for suspend functions.
I am also aware, that all my database operations are running synchronously, and I could use r2dbc to make them asynchronously (as long as my database provides the driver implementing the specification), but I think that my question does not relate to how I communicate with the database but more about how spring handles suspending calls withing #Transactional annotated methods.
What are your thoughts and recommendations here? I am definitely not the first dev who does suspending work in a transactional method in Kotlin, and still I am not able to find helpful resources on this issue.
Thanks guys!
JPA isn't supported with Coroutine Transactions as JPA is fully synchronous. Coroutine Transaction propagation works only with technologies that provide a reactive integration such as MongoDB, R2DBC, or Neo4j.
JPA assumes an imperative programming model hence its transaction manager stores transactional state in ThreadLocal storage. Reactive integrations and specifically Coroutines employ Coroutines context/Reactor's subscription context to keep track of the transaction status. There's no link between ThreadLocal and the context feature of Coroutines/Project Reactor.
Going forward, using blocking integrations such as JPA require special attention in the context of coroutines and their transactional scope needs to be constrained onto a single thread.

Deep understanding of Spring boot with HikariCP

I have a spring boot app which uses spring data and hikaricp for db connection pooling. I noticed the following behaviour that looks strange to me:
I have one method which is not transactional and in that method several db queries are executed using spring data repositories
public void testMethod(final Long firstRepositoryId, final Long secondRepositoryId) {
final DomainObject result = firstRepository.findById(firstRepositoryId);
// here there's some code that is processing the result without db queries
secondRepository.findById(secondRepositoryId);
// some more logic here without additional db queries
}
So as expected when there's no transaction on the method then the spring data methods opens a transaction for executing the query and complete it after the methods returns. I have enabled transaction logging so there's the following log output:
2021-06-03 15:34:30.961 TRACE c681f76a-5d7e-41d5-9e50-fb6f96169681 --- [tp659271212-291] o.s.t.i.TransactionInterceptor : Getting transaction for [com.test.FirstRepository.findById]
2021-06-03 15:34:30.966 TRACE c681f76a-5d7e-41d5-9e50-fb6f96169681 --- [tp659271212-291] o.s.t.i.TransactionInterceptor : Completing transaction for [com.test.FirstRepository.findById]
2021-06-03 15:34:30.967 TRACE c681f76a-5d7e-41d5-9e50-fb6f96169681 --- [tp659271212-291] o.s.t.i.TransactionInterceptor : Getting transaction for [com.test.SecondRepository.findById]
2021-06-03 15:34:30.972 TRACE c681f76a-5d7e-41d5-9e50-fb6f96169681 --- [tp659271212-291] o.s.t.i.TransactionInterceptor : Completing transaction for [com.test.SecondRepository.findById]
Everything seems to be exactly how I expects to be. The thing I can't understand is the hikari behaviour. This method is invoked within a http request. A connection is taken from hikari cp right after the execution of the firstRepository.findById but this connection is returned in the pool only after the http controller returns response. What I expect is that a connection is taken after a transaction is opened and returned back after the transaction is completed. Is there something that I miss or maybe I have some wrong configuration?
P.S. I'm monitoring the active hikari connections through the spring boot actuator prometheus data. And to be able to reproduce the behavior I explained above I'm suspending the connection thread with several debug breakpoints.
I found out what causes this behaviour- it's Spring functionality to maintain the hibernate session in view in order to be able to retrieve lazy loaded data in the view. In order to disable this you need the following property:
spring.jpa.open-in-view=false
Here's another SO post where is explained what it does:
What is this spring.jpa.open-in-view=true property in Spring Boot?

JMS commit fails

We have an application that uses JMS with Tibco messaging server. It’s implemented with Spring Boot.
Our sessions are transacted sessions and the acknowledge mode is set to auto.
We can receive the messages sent to the queue but for some reason that commit() method fails.
This is the error:
2018-07-13 15:50:35.858 WARN 2576 --- [enerContainer-8] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
javax.jms.TransactionRolledBackException: Commit failed
2018-07-13 15:50:35.914 WARN 2576 --- [enerContainer-8] o.s.j.l.DefaultMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'queue' - trying to recover. Cause: Commit failed; nested exception is javax.jms.JMSException: operation='ack' cause='Illegal state' queue='queue'
I should mention two things:
I see the commit() failure and stack trace, only when I run in debug mode. If I let the war to just run, I don’t see any trace of commit failure in the logs. I can tell that we received the messages, but can’t tell whether the commit() failed or not.
If we use the default JMS implementations of Spring Boot which is ActiveMQ, then the commit() does not fail whether its in debug mode or not, it only happens with Tibco.
Does anybody have any idea that why the commit() fails? When the commit fails, the transaction is rolled back and the messages won’t be cleared from the queue.
Why I see this error only in debug mode? OR: it indeed, does happen when I run the war but just not logged?
Below please find the complete stack trace:
15:50:35.858 [DefaultMessageListenerContainer-8] WARN o.s.j.l.DefaultMessageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
javax.jms.TransactionRolledBackException: Commit failed
at com.tibco.tibjms.Tibjmsx.buildException(Tibjmsx.java:596)
at com.tibco.tibjms.TibjmsxSessionImp._confirmTransacted(TibjmsxSessionImp.java:3251)
at com.tibco.tibjms.TibjmsxSessionImp._confirm(TibjmsxSessionImp.java:3643)
at com.tibco.tibjms.TibjmsxSessionImp._commit(TibjmsxSessionImp.java:2898)
at com.tibco.tibjms.TibjmsxSessionImp.commit(TibjmsxSessionImp.java:4860)
at org.springframework.jms.support.JmsUtils.commitIfNecessary(JmsUtils.java:218)
at org.springframework.jms.listener.AbstractMessageListenerContainer.commitIfNecessary(AbstractMessageListenerContainer.java:776)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:680)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076)
at java.lang.Thread.run(Unknown Source)
2018-07-13 15:50:35.914 WARN 2576 --- [enerContainer-8] o.s.j.l.DefaultMessageListenerContainer : Setup of JMS message listener invoker failed for destination 'queue' - trying to recover. Cause: Commit failed; nested exception is javax.jms.JMSException: operation='ack' cause='Illegal state' queue='queue'
2018-07-13 15:50:36.543 INFO 2576 --- [enerContainer-8] o.s.j.l.DefaultMessageListenerContainer : Successfully refreshed JMS Connection
15:50:36.543 [DefaultMessageListenerContainer-8] INFO o.s.j.l.DefaultMessageListenerContainer - Successfully refreshed JMS Connection
This EMS exception happens when some of your messages within that transaction expired in the meantime. Just tried this one myself.
When you run outside of debugging mode, things seem to be quick enough. But when you are in debugging mode, your time before you commit() is much longer. So if your producer's time-to-live expires in the meantime, the commit assumes that something is wrong (EMS knows that there should be e.g. 5 messages in this transaction, but one of them already expired) and throws this exception.
To verify your producer's time-to-live, see the last option of your MessageProducer.send() call or msgProducer.setTimeToLive() and note, this is a time in millseconds, not seconds. Another way to check if this is the issue, is to run in debug mode and be 'really quick' with continuing your thread. That might change your behaviour.

WebSphere 8.5.5 and JMS annotations crash server application

I'm deploying an app that makes use of Spring 4.2.5, Hibernate 4.2.8, and JMS 1.1 on to WebSphere 8.5.5 and Oracle 12.
Resources such as the database connection manager, and JMS connection factory are set in the server and wired into the Spring app using JNDI.
When the app starts I see this in the logs:
[3/18/16 15:18:32:717 EST] 0000008b SystemOut O [B#631dd237/Set;
at org.springframework.jms.annotation.JmsListenerAnnotationBeanPostProcessor$1.inspect(JmsListenerAnnotationBeanPostProcessor.java:202)
at org.springframework.jms.annotation.JmsListenerAnnotationBeanPostProcessor$1.inspect(JmsListenerAnnotationBeanPostProcessor.java:198)
at org.springframework.core.MethodIntrospector$1.doWith(MethodIntrospector.java:72)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:495)
at org.springframework.core.MethodIntrospector.selectMethods(MethodIntrospector.java:68)
at org.springframework.jms.annotation.JmsListenerAnnotationBeanPostProcessor.postProcessAfterInitialization(JmsListenerAnnotationBeanPostProcessor.java:197)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1559)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 58 more
[3/18/16 15:18:32:718 EST] 0000008b SystemOut O [FIAT-CSP-NA] [WebContainer : 0] 2016-03-18 15:18:32,718 [INFO ] org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean: Closing JPA EntityManagerFactory for persistence unit default
As you can see it appears there is some sort of error in the JMSListenerAnnotationBeanPostProcessor, followed by a message indicating that the JPA entity manager is shutting down.
I presume from this that there is a JMS problem which is shutting down the app.
Has anyone seen this? Do you know what might be the issue?
I'm really stuck on this.
The answer turned out to be class path issues. (Isn't everything on Websphere!)
I needed to remove several jars from the war file that where conflicting with jars web sphere supplied.

Resources