13

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?

Kromster
  • 7,181
  • 7
  • 63
  • 111
Dinesh M
  • 674
  • 2
  • 7
  • 18
  • how about a durable message from you --> 3rd party?, What is your ack system with third party? i.e. how do you know if they are up, even if they are up they didnt error-out and tossed your msg? --what contract do you have with 3rd party? – Sendi_t May 15 '15 at 18:45
  • I’m using RESTful web service contract to interact with third party application. If server is down it will try for couple of time to connect then we receive fault error message if failed or connection lost message. – Dinesh M May 15 '15 at 19:16
  • 1
    Is it possible you could set up a Dead Letter Queue and then periodically move these messages back into the main queue? – BretC May 15 '15 at 21:50

4 Answers4

8

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?

Community
  • 1
  • 1
GionJh
  • 2,742
  • 2
  • 29
  • 68
7

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.

Will Hartung
  • 115,893
  • 19
  • 128
  • 203
  • 2
    "don't store messages in a JMS queue" can you further explain this? The queue can be persistent, so why not store in it? – digital illusion Nov 30 '16 at 14:24
  • There are cases when you are required to process the messages in strict sequence. In that cases the bad messages are kept in the queue as long they are not successfully consumed. – abbas May 16 '19 at 12:09
5

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();
    }
sri
  • 61
  • 4
0

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.

Shashi
  • 14,980
  • 2
  • 33
  • 52