Dinesh M
Dinesh M

Reputation: 724

How to hold messages in JMS Message Queue if there are any error after consuming the message?

My scenario is - I post message in to queue and once message is consumed I am sending it to third party middleware application. If that middleware application is down then my posted message gone for toss. I do not want to lose that message if middleware application is down instead I want it to be on hold or waiting in the queue. Please suggest, how to handle this scenario?

Upvotes: 13

Views: 21624

Answers (4)

Will Hartung
Will Hartung

Reputation: 118593

JMS Queues are not message stores.

If you have a "bad message" for which the processing continues to fail, then the JMS server (if configured) will inevitably dump that message to a a "Dead Message Queue", which will slowly fill up until a different process drains it.

You don't want to keep bad messages in the queue, as they can potentially block the queue (imagine you have 10 consumers, and the top 10 messages are all bad, so all the processes do is continue to flail on bad messages -- stalling the queue).

So, you need some mechanism to store the messages in to an exception sink, where they can then later be injected in to the main queue for processing.

The dead message queue is not this mechanism (don't store messages in a JMS queue), rather it can be a mechanism to ROUTE exceptional messages to a more permanent storage area (i.e. a db table or something else).

Once there, they can be vetted (automatically, manually, whatever) and either redelivered or canceled.

But the key point is you need an external mechanism for this, the JMS Server alone isn't the appropriate place for these kind of messages.

Upvotes: 7

sri
sri

Reputation: 61

This can be acheived my using session acknowledgement. For this first modify your producer code to use Session.AUTO_ACKNOWLEDGE. While creating Queue session, make AUTO_ACKNOWLEDGE as false. That means consumer has to acknowledge. When the consumer sends acknowledgement of message, then the message will be deleted from the queue, otherwise it will remain in the queue.

Below is the producer code.

try {
        QueueConnectionFactory qcf = AppUtils.getQueueConnectionFactory(); 
        Queue q = AppUtils.getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueSender qSender = qSession.createSender(q);

        qConnection.start();
        TextMessage msg = qSession.createTextMessage("Hello");
        qSender.send(msg);

        qSender.close();
        qConnection.close();

    } catch (JMSException e) {
        // log your error to log file
        e.printStackTrace();
    }

On the consumer side you have to do the same thing, create a queue session with AUTO_ACKNOWLEDGE as false.

After working on your message, you can send acknowledge to delete the message from the queue or the message will remain in the queue.

try {
        QueueConnectionFactory qcf = getQueueConnectionFactory(); 
        Queue q = getDestination();
        QueueConnection qConnection = qcf.createQueueConnection();
        QueueSession qSession = qConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

        QueueReceiver qReceiver = qSession.createReceiver(q);

        qConnection.start();
        Message msg = qReceiver.receive();

  // here send your message to third party application 
  //if your third party application is down 
        if(thirdpartyapp is down){
          //here you can raise an exception 
          //or just do nothing 
          // you're not sending acknowledgement here so the msg will 
           //remain in the queue
        }else{      
          msg.acknowledge();//here youre sending ack, so msg will be deleted
          qReceiver.close();
          qConnection.close();
        }

    } catch (JMSException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

Upvotes: 5

GionJh
GionJh

Reputation: 2884

You should create the session like this:

Session session = connection.createSession(false,
                       Session.CLIENT_ACKNOWLEDGE);

when you try to deliver the message to your third party app:

  • If it's working you should acknoledge the message.

  • If it is down you should'nt acknwoledge it, this way the JMS provider will be able to rediliver it,and the message will not be lost. message.acknowledge();

Also, you can take a look at this: JMS AUTO_ACKNOWLEDGE when is it acknowledged?

Upvotes: 8

Shashi
Shashi

Reputation: 15263

Although, it's not very clear how your application that consumes messages is designed, I suggest you modify consumer application to consume messages inside a local transaction and post message to third party middle-ware application. If post is successful, then you can commit the transaction which will remove the message from JMS queue. In case your application fails to post message, you can simply rollback transaction which will make the message to reappear in JMS queue. That message will be delivered again.

Upvotes: 0

Related Questions