I would like to clarify behavior of the Tibco bus (6.1) used via Spring (4.1) JMS config - with and without ErrorHandler specified, and for a specific case of the TransactionRolledBackException.
I configure JMS listener with the "transacted" mode as following:
<jms:listener-container connection-factory="singleConnectionFactory"
acknowledge="transacted" task-executor="myTaskExecutor" concurrency="${my.queue.concurrency}">
<jms:listener destination="${queue.destination}" ref="myProcessor" method="processMyMessage" />
</jms:listener-container>
and also set 'maxRedelivery' for the queue to 2.
Here are the scenarios of processing an event in the myProcessor.processMyMessage():
- message is processed successfully; Result: message is ACK'ed and removed from the queue
- a Runtime exception is thrown , either by business logic or by the Spring container (say OOM or HectorException); Result: message is not ACK'ed, put back on the bus and redelivered up to 2 times
- org.springframework.jms.TransactionRolledBackException is thrown (by Spring, I assume) - since it is a Runtime exception the resulting behavior is the same as in 2. (is this correct?)
Now, I am adding an explicit ErrorHandler to better log some runtime exceptions:
<jms:listener-container connection-factory="singleConnectionFactory"
acknowledge="transacted" task-executor="myTaskExecutor" concurrency="${my.queue.concurrency}"
error-handler="myErrorHandler">
<jms:listener destination="${queue.destination}" ref="myProcessor" method="processMyMessage" />
</jms:listener-container>
And the following implementation of the ErrorHandler, where we swallow TransactionRolledBackException:
import org.springframework.jms.TransactionRolledBackException;
import org.springframework.util.ErrorHandler;
public class JMSListenerErrorHandler implements ErrorHandler {
@Override
public void handleError(Throwable t) {
if (t.getCause() instanceof TransactionRolledBackException) {
log.warn("JMS transaction rollback; reason: " + t.getMessage(), t);
} else {
log.error(t.getMessage(), t);
throw new RuntimeException(t);
}
}
What is going to happen for each of the use cases? Here is my guess:
- no change
- no change - this Runtime exception is re-thrown, so the message will not be ACK'ed and will be redelivered up to 2 time
- TransactionRolledBackException: when I handle this exception in the ErrorHandler - is this happening AFTER the TX was already rolled back (as the name RolledBack suggests) and message was marked as not ACK'ed, thus, causing it to be redelivered as in the case 2. ? Or do I effectively cause this messaged to be ACK'ed by swallowing this exception?
Couple more questions:
- under what conditions would Spring throw an org.springframework.jms.TransactionRolledBackException ?
- is TransactionRolledBackException treated any different than any other Runtime exception?
Thank you,
Marina