Quantcast

camel-jpa and PersistenceException

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

camel-jpa and PersistenceException

jamest
I am using camel-jpa to poll messages from a database.  As recommended for recovery on database failures, the persistence unit is configured with Tomcat jdbc connection pool as the datasource and uses a test-on-borrow strategy to validate connections.

The route still fails to recover if the database goes down.  I was able to recreate the problem using an HSQL instance that I forced to go down during route execution.  The stack trace shows that the PersistenceException is thrown from JpaConsumer's doInTransaction().

As I was researching the problem I came across CAMEL-9608 which introduced catching a PersistenceException and forcing the next poll to create a new EntityManager.  It only performs this when the PersistenceException is thrown from processBatch()

So my question is, if PersistenceException can be thrown at TransactionTemplate.execute() then is there any reason why the try/catch for PersistenceException can't wrap this too?

From reading this forum I know that the JPA component expects the EntityManager to handle the connection recovery but I'm not on solid ground yet in determining how the EntityManager is supposed to react under these circumstances.  It seems like the locally stored EntityManager just doesn't give up this bad connection.

2017-03-09 08:59:30.789  WARN 14085 --- [0 - jpa://color] o.a.camel.component.jpa.JpaConsumer      : Consumer Consumer[jpa://color?consumeDelete=false&consumer.delay=4000&consumer.lockModeType=NONE&consumer.nativeQuery=select+*+from+colors&maximumResults=1] failed polling endpoint: jpa://color?consumeDelete=false&consumer.delay=4000&consumer.lockModeType=NONE&consumer.nativeQuery=select+*+from+colors&maximumResults=1. Will try again at next poll. Caused by: [javax.persistence.PersistenceException - java.sql.SQLTransientConnectionException: connection exception: connection failure: java.net.SocketException: Broken pipe]

javax.persistence.PersistenceException: java.sql.SQLTransientConnectionException: connection exception: connection failure: java.net.SocketException: Broken pipe
	at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1700) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:48) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
	at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.enlistInCurrentTransaction(ExtendedEntityManagerCreator.java:401) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
	at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.doJoinTransaction(ExtendedEntityManagerCreator.java:379) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
	at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:330) ~[spring-orm-4.3.7.RELEASE.jar:4.3.7.RELEASE]
	at com.sun.proxy.$Proxy61.joinTransaction(Unknown Source) ~[na:na]
	at org.apache.camel.component.jpa.JpaConsumer$1.doInTransaction(JpaConsumer.java:103) ~[camel-jpa-2.18.2.jar:2.18.2]
	at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
	at org.apache.camel.component.jpa.JpaConsumer.poll(JpaConsumer.java:100) ~[camel-jpa-2.18.2.jar:2.18.2]
	at org.apache.camel.impl.ScheduledPollConsumer.doRun(ScheduledPollConsumer.java:175) [camel-core-2.18.2.jar:2.18.2]
	at org.apache.camel.impl.ScheduledPollConsumer.run(ScheduledPollConsumer.java:102) [camel-core-2.18.2.jar:2.18.2]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_101]
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_101]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_101]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_101]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_101]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_101]
	at java.lang.Thread.run(Thread.java:745) [na:1.8.0_101]
Caused by: java.sql.SQLTransientConnectionException: connection exception: connection failure: java.net.SocketException: Broken pipe
	at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.jdbc.JDBCConnection.setAutoCommit(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at sun.reflect.GeneratedMethodAccessor21.invoke(Unknown Source) ~[na:na]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_101]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_101]
	at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126) ~[tomcat-jdbc-8.5.11.jar:na]
	at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108) ~[tomcat-jdbc-8.5.11.jar:na]
	at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81) ~[tomcat-jdbc-8.5.11.jar:na]
	at com.sun.proxy.$Proxy51.setAutoCommit(Unknown Source) ~[na:na]
	at org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor.begin(AbstractLogicalConnectionImplementor.java:67) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl.begin(LogicalConnectionManagedImpl.java:238) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.begin(JdbcResourceLocalTransactionCoordinatorImpl.java:214) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.engine.transaction.internal.TransactionImpl.begin(TransactionImpl.java:52) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1512) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
	at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:45) ~[hibernate-entitymanager-5.0.12.Final.jar:5.0.12.Final]
	... 16 common frames omitted
Caused by: org.hsqldb.HsqlException: connection exception: connection failure: java.net.SocketException: Broken pipe
	at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.ClientConnection.execute(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.ClientConnection.setAttribute(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	at org.hsqldb.ClientConnection.setAutoCommit(Unknown Source) ~[hsqldb-2.3.3.jar:2.3.3]
	... 30 common frames omitted
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: camel-jpa and PersistenceException

Claus Ibsen-2
Hi

You could try to patch the code yourself and run with a camel-jpa JAR
with your code changes to see what you can get working for you, and
then come back here with the code changes for further discussion and
see what we can do for camel-jpa.

On Thu, Mar 9, 2017 at 7:42 PM, jamest <[hidden email]> wrote:

> I am using camel-jpa to poll messages from a database.  As recommended for
> recovery on database failures, the persistence unit is configured with
> Tomcat jdbc connection pool as the datasource and uses a test-on-borrow
> strategy to validate connections.
>
> The route still fails to recover if the database goes down.  I was able to
> recreate the problem using an HSQL instance that I forced to go down during
> route execution.  The stack trace shows that the PersistenceException is
> thrown from JpaConsumer's doInTransaction().
>
> As I was researching the problem I came across CAMEL-9608 which introduced
> catching a PersistenceException and forcing the next poll to create a new
> EntityManager.  It only performs this when the PersistenceException is
> thrown from processBatch()
>
> So my question is, if PersistenceException can be thrown at
> TransactionTemplate.execute() then is there any reason why the try/catch for
> PersistenceException can't wrap this too?
>
> From reading this forum I know that the JPA component expects the
> EntityManager to handle the connection recovery but I'm not on solid ground
> yet in determining how the EntityManager is supposed to react under these
> circumstances.  It seems like the locally stored EntityManager just doesn't
> give up this bad connection.
>
>
>
>
>
>
> --
> View this message in context: http://camel.465427.n5.nabble.com/camel-jpa-and-PersistenceException-tp5795205.html
> Sent from the Camel - Users mailing list archive at Nabble.com.



--
Claus Ibsen
-----------------
http://davsclaus.com @davsclaus
Camel in Action 2: https://www.manning.com/ibsen2
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: camel-jpa and PersistenceException

jamest
It doesn't look very clean perhaps but adding the try/catch around the whole transactionTemplate.execute() block worked for us.

    https://github.com/jamesET/camel/blob/master/components/camel-jpa/src/main/java/org/apache/camel/component/jpa/JpaConsumer.java

As the stack trace confirms, persistence exceptions can be thrown just from the back-end mechanics that start the transaction and could potentially happen at other points in the poll method, eg query.getResultList().  And if the  the entity manager should be refreshed in case of rollback, or even for a hard disconnect in my case, then it seems reasonable to do something like this.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: camel-jpa and PersistenceException

jamest
Anyone have feedback on the patched version?  

Manual testing with the patched version in our product was successful, basically just starting/stopping the database and observing that the component was always able to reconnect.  Without this change it continues to throw the exception first reported.

I haven't worked out a good unit test strategy for this but I have a couple of ideas using an embedded hsqldb.  

Loading...