Matthias Brück
Matthias Brück

Reputation: 204

Stop MDB Message Redelivery

I've got a StatelessSessionBean, what, on calling a specific method, creates a MapMessage to be sent to an MDB.

QueueConnection connection = null;
QueueSession mSession = null;
QueueSender messageProducer = null;
try {
    QueueConnectionFactory connectionFactory = (QueueConnectionFactory) home(session).getCTX().lookup(DocumentManagementTransactionUtil.QUEUE_CONNECTION_FACTORY);
    connection = connectionFactory.createQueueConnection();
    mSession = connection.createQueueSession(false, Session.CLIENT_ACKNOWLEDGE);
    Queue dest = (Queue) home.getCTX().lookup(DocumentManagementTransactionUtil.QUEUE_DESTINATION);
    messageProducer = mSession.createSender(dest);
    messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
    messageProducer.send(createJMSMessageFordocMessageReceiver(mSession, session, idnr, debugCode));
} catch (Exception ex) {
    log.error("failed to start DocumentTransfer MDB", ex);
    throw new AsaleException("failed to start DocumentTransfer MDB", ex);
} finally {
    try { if (messageProducer != null) messageProducer.close(); } catch (Exception e) { }
    try { if (mSession != null) mSession.close(); } catch (Exception e) { }
    try { if (connection != null) connection.stop(); connection.close(); } catch (Exception e) { }
}


Now in my onMessage method of my MDB I read out all I need from my message and acknowledge it.

MapMessage msg = (MapMessage) message;
project = msg.getLong("project");
Long lang = msg.getLong("lang");
int firm = msg.getInt("opFirm");
int sub = msg.getInt("opSub");
long user = msg.getLong("user");
int debugCode = msg.getInt("debugCode");

log.debug(project + prelog + "DocumentManagementMDBean... Retrieved Message: User: " + user + " Project: " + project + " JMS MessageID: " + message.getJMSMessageID() + " Redelivered: " + message.getJMSRedelivered());
message.acknowledge();


and a lengthy operation starts which takes an undefined time (1 up to X minutes) without returning from the onMessage Method.

After 5 minutes my message, as I can see from the ID and the redelivered state, gets redelivered, even though I acknowledged it before.

Did I do something wrong or is there a way to tell the System not to redeliver the message?


Edit:
@TransactionManagement(TransactionManagementType.BEAN) @MessageDriven(mappedName = DocumentManagementTransactionUtil.MAPPED_NAME, activationConfig = { @ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", propertyValue = DocumentManagementTransactionUtil.QUEUE_DESTINATION), @ActivationConfigProperty(propertyName = "dLQMaxResent", propertyValue = "0")})

Upvotes: 1

Views: 774

Answers (1)

Steve C
Steve C

Reputation: 19435

Everything about message driven beans is transactional.

If a message cannot be delivered to it's queue/topic then your transaction will fail and be rolled back.

If a message cannot be processed for any reason then the transaction in which the MDB is executed will be rolled back. In this case the specs mandate that the container retry the message delivery to the MDB.

In your case, it looks like your transaction is timing out, following which any transactional operation (such as database access or EJB call) will fail and an exception is thrown. The container is subsequently retrying to process the message.

Generally speaking you should not attempt to execute long running processes in any EJB method (including message driven beans).

As you have tagged this with wildfly I guess you're using a Java EE 7 implementation. If this is the case you might consider using the JSR-352 Batch Processing API for your purpose.

Upvotes: 1

Related Questions