MDB Failure Handling: Difference between revisions
Line 19: | Line 19: | ||
The behavior of the WildFly/HornetQ-Backed MDB container in presence of a message processing failure depends on the transactional context (container manager or bean managed) and whether the error materializes as an unchecked application exception or a generic unchecked exception. The MDB's onMessage() method cannot throw checked exceptions. | The behavior of the WildFly/HornetQ-Backed MDB container in presence of a message processing failure depends on the transactional context (container manager or bean managed) and whether the error materializes as an unchecked application exception or a generic unchecked exception. The MDB's onMessage() method cannot throw checked exceptions. | ||
The most common situation is an MDB configured to use container managed transactions, with the transactional attribute set to REQUIRED. The message delivery and processing is enclosed by a JTA transaction that is started by the MDB container. Upon starting the transaction, the MDB container enlists the XAResource exposed by the JMS provider with | The most common situation is an MDB configured to use container managed transactions, with the transactional attribute set to REQUIRED. The message delivery and processing is enclosed by a JTA transaction that is started by the MDB container. Upon starting the transaction, the MDB container enlists the XAResource exposed by the JMS provider with the transaction. The container's transaction interceptor simply acknowledges the presence of the JTA transaction and proceeds with the invocation with the "caller" transaction. | ||
If the MDB business code throws a non-application unchecked exception, the JTA transaction started by the MDB container is automatically rolled back: the MDB container's transactional interceptor catches the RuntimeException and rolls back the transaction, by invoking <tt>javax.transaction.Transaction.setRollbackOnly()</tt>. The MDB instance that triggered the failure is destroyed. as required by the specification. The @PreDestroy callback, if exists, is invoked, and the instance is discarded from the pool. Upon re-delivery, if any, a new MBD instance to handle the message will be created. Since the delivery transaction is rolled back, the message becomes available for delivery again, and it is re-delivered by the built-in HornetQ mechanism, described [[WildFly_HornetQ_Message_Redelivery_on_Failure_and_the_Dead_Letter_Queue#Overview|here]]. | If the MDB business code throws a non-application unchecked exception, the JTA transaction started by the MDB container is automatically rolled back: the MDB container's transactional interceptor catches the RuntimeException and rolls back the transaction, by invoking <tt>javax.transaction.Transaction.setRollbackOnly()</tt>. The MDB instance that triggered the failure is destroyed. as required by the specification. The @PreDestroy callback, if exists, is invoked, and the instance is discarded from the pool. Upon re-delivery, if any, a new MBD instance to handle the message will be created. Since the delivery transaction is rolled back, the message becomes available for delivery again, and it is re-delivered by the built-in HornetQ mechanism, described [[WildFly_HornetQ_Message_Redelivery_on_Failure_and_the_Dead_Letter_Queue#Overview|here]]. |
Revision as of 19:41, 25 April 2017
Internal
Relevance
EAP 6.4.10
Overview
This article addresses failure handling in an MDB context. It was written while experimenting with EAP 6.4 and a HornetQ-based messaging subsystem.
Failure Handling Specification
JSR 318 Enterprise JavaBeans Version 3.1 EJB Core Contract and Requirements, Section 5.4.18 "Dealing with Exceptions" mentions that MDBs should not throw RuntimeExceptions. If a RuntimeExceptions that is not an application exception, the container will transition the MDB instance that triggered the exception in the "does not exist" state. If the MDB uses bean-managed transaction demarcation, the container should not acknowledge the message. From the client perspective, the message consumer continues to exist. If the client continues to send messages to the destination associated with the container, the container can delegate the message to another MDB instance.
WildFly/HornetQ-Backed MDB Container Behavior on Failure
The behavior of the WildFly/HornetQ-Backed MDB container in presence of a message processing failure depends on the transactional context (container manager or bean managed) and whether the error materializes as an unchecked application exception or a generic unchecked exception. The MDB's onMessage() method cannot throw checked exceptions.
The most common situation is an MDB configured to use container managed transactions, with the transactional attribute set to REQUIRED. The message delivery and processing is enclosed by a JTA transaction that is started by the MDB container. Upon starting the transaction, the MDB container enlists the XAResource exposed by the JMS provider with the transaction. The container's transaction interceptor simply acknowledges the presence of the JTA transaction and proceeds with the invocation with the "caller" transaction.
If the MDB business code throws a non-application unchecked exception, the JTA transaction started by the MDB container is automatically rolled back: the MDB container's transactional interceptor catches the RuntimeException and rolls back the transaction, by invoking javax.transaction.Transaction.setRollbackOnly(). The MDB instance that triggered the failure is destroyed. as required by the specification. The @PreDestroy callback, if exists, is invoked, and the instance is discarded from the pool. Upon re-delivery, if any, a new MBD instance to handle the message will be created. Since the delivery transaction is rolled back, the message becomes available for delivery again, and it is re-delivered by the built-in HornetQ mechanism, described here.
If the MDB business code throws an application unchecked exception,
If the MDB uses container managed transactions but the transactional attribute is set to NOT_SUPPORTED TODO.
If the MDB uses bean managed transactions TODO.
Message Delivery Occurs in a Non-Transactional Context
How to Handle Failure in a Transactional Context
Redelivery and Dead Letter Queue
The message redelivery count on failure is not an attribute of an individual MDB container, as the "dLQMaxResent" configuration attribute seems to suggest, but of the HornetQ destination. In EAP 6.4.10, "dLQMaxResent" is ignored. If an MDB fails to process a message in a transactional context, the transaction is rolled back and the message is "put back on the queue". The message will be redelivered by the HornetQ destination, subject to redelivery rules sent on the destination. Upon failure, the message will be redelivered to the same MDB container, if it is the only consumer for that queue, or to a different MDB container if there is more than one MDB container listening to the queue.