users@glassfish.java.net

Re: infinite message redelivery in the case of a DatabaseException at commit time

From: Amy Kang <amy.kang_at_oracle.com>
Date: Wed, 13 Apr 2011 17:00:55 -0700

It's likely the redeliveries were result of TM rolling back the
distributed transaction that has failed to commit. If that is the
case, you can check Message.getJMSRedelivered() in onMessage(), if
it's true, do a dup-key check before the step of storing data in
database, if the key already exists, then decide what to do in
onMessage() based on the application processing needs.

amy

On 11-04-13 08:26 AM, forums_at_java.net wrote:
> Hi,
>
> I struggle with an infinte redelivery of some messages, when using CMT
> for my
> MDB's in the case of a DatabaseException at commit time. I'm using
> Glassfish
> 3.1 in conjunction with a remote conventional OpenMQ cluster (Version 4.4
> Update 2) and a PostgreSQL 9.0.3 - No XA Resources are configured. A
> little
> bit more in detail, I have plain MDB as follow, which just receives a
> message
> and stores some data in the database:
>
> @MessageDriven(mappedName = "jms/myQueue", activationConfig = {
> @ActivationConfigProperty(propertyName = "destinationType",
> propertyValue =
> "javax.jms.Queue"),
> @ActivationConfigProperty(propertyName = "messageSelector",
> propertyValue =
> "someKey like '" + "foo%") })
> public class MyMDB implements MessageListener {
> @PersistenceContext(unitName = "my-pu")
> private EntityManager entityManager;
> @Override
> public void onMessage(final Message _message) {
> ....
> entityManager.persist(entity);
> }
> }
>
>
> In some cases a database constraint is violated resulting in a
> org.postgresql.util.PSQLException thrown at commit time:
>
>
>
> Exception [EclipseLink-4002] (Eclipse Persistence Services -
> 2.2.0.v20110202-r8913):
> org.eclipse.persistence.exceptions.DatabaseException
> Internal Exception: org.postgresql.util.PSQLException: ERROR:
> duplicate key
> ....
> at
> org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.issueSQLbeforeCompletion(RepeatableWriteUnitOfWork.java:331)
>
> at
> org.eclipse.persistence.transaction.AbstractSynchronizationListener.beforeCompletion(AbstractSynchronizationListener.java:157)
>
> at
> org.eclipse.persistence.transaction.JTASynchronizationListener.beforeCompletion(JTASynchronizationListener.java:68)
>
> at
> com.sun.jts.jta.SynchronizationImpl.before_completion(SynchronizationImpl.java:99)
>
> at
> com.sun.jts.CosTransactions.RegisteredSyncs.distributeBefore(RegisteredSyncs.java:158)
>
> at
> com.sun.jts.CosTransactions.TopCoordinator.beforeCompletion(TopCoordinator.java:2561)
>
> at
> com.sun.jts.CosTransactions.CoordinatorTerm.commit(CoordinatorTerm.java:279)
>
> at
> com.sun.jts.CosTransactions.TerminatorImpl.commit(TerminatorImpl.java:250)
> at com.sun.jts.CosTransactions.CurrentImpl.commit(CurrentImpl.java:623)
> at
> com.sun.jts.jta.TransactionManagerImpl.commit(TransactionManagerImpl.java:319)
>
> at
> com.sun.enterprise.transaction.jts.JavaEETransactionManagerJTSDelegate.commitDistributedTransaction(JavaEETransactionManagerJTSDelegate.java:173)
>
> at
> com.sun.enterprise.transaction.JavaEETransactionManagerSimplified.commit(JavaEETransactionManagerSimplified.java:873)
>
> at
> com.sun.ejb.containers.BaseContainer.completeNewTx(BaseContainer.java:5115)
>
> at
> com.sun.ejb.containers.BaseContainer.postInvokeTx(BaseContainer.java:4880)
> at
> com.sun.ejb.containers.MessageBeanContainer.afterMessageDeliveryInternal(MessageBeanContainer.java:1207)
>
> at
> com.sun.ejb.containers.MessageBeanContainer.afterMessageDelivery(MessageBeanContainer.java:1180)
>
> at
> com.sun.ejb.containers.MessageBeanListenerImpl.afterMessageDelivery(MessageBeanListenerImpl.java:86)
>
> at
> com.sun.enterprise.connectors.inbound.MessageEndpointInvocationHandler.invoke(MessageEndpointInvocationHandler.java:143)
>
> at $Proxy261.afterDelivery(Unknown Source)
> at com.sun.messaging.jms.ra.OnMessageRunner.run(OnMessageRunner.java:328)
> at com.sun.enterprise.connectors.work.OneWork.doWork(OneWork.java:114)
> at
> com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.performWork(ThreadPoolImpl.java:497)
>
> at
> com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.jav
>
>
>
> Whenever this happens, the same message will be redelivered over and over
> again and never send to the DMQ, even though property the useDMQ is to
> true
> for the queue. I'm able to work around this issue in two ways:
> First,whenever
> I flush the persistence context right after persisting the entity and a
> PersistenceException is thrown in the onMessage(..) method, the
> message is
> moved to the DMQ as expected. The same happens when the bean manage the
> transaction by itself (BMT):
>
>
>
> @Override
> public void onMessage(final Message _message) {
> try {
> tx.begin();
> ...
> entityManager.persist(entity);
> tx.commit();
> } catch (Exception e) {
> try {
> tx.rollback();
> } catch (Exception e1) { throw new RuntimeException(e); }
> throw new RuntimeException(e);
> }
> }
>
>
> At present I have no clear idea why this happens, whether this is a
> bug or I
> have an unclear understanding of what is happening behind the scenes.
>
> Any help is appreciated.
>
> Thanks in advance, Carsten
>
>
> --
>
> [Message sent by forum member 'c_krebs']
>
> View Post: http://forums.java.net/node/791533
>
>