简体   繁体   中英

IBM MQQueue Safest way to get all messages

I have a simple java program to transfer messages from queue A to queue B using IBM MQ.

My program works fine, but what I am concerned about is losing messages. I know that .get() removes the message from queue A. So of course, there is a brief moment where I have "got" a message from queue A, and I have not yet placed it in queue B. If my program were to crash during this time - the message would be lost.

To combat this, I am writing the current message to the logs. Then, if the program crashes, we can enter the message back into the queue manually.

However - what if the program crashes from an IOException ? Now the message is gone from queue A, has not been .put() in queue B, and hasn't been written to the logs.

The way I see it, I have two options:

Browse the message first: I know that I can browse the message before "getting" it, although I'm a bit confused about how this affects the number of messages in the queue, and if it creates a duplicate etc.

Write the message back to queue A: In theory, if we "get" the message from queue A, we shouldn't have a problem "putting" it back to queue A, if for some reason we can't connect to queue B.

Could someone clarify the proper way to browse a message first - or perhaps suggest a third option I haven't thought of?

while (true) {

  try {

    // Clear the MQMessage
    theMessage.messageId = MQConstants.MQMI_NONE;
    theMessage.correlationId = MQConstants.MQCI_NONE;

    // Get the message from queue A
    queueA.get(theMessage, gmo);

    // Read the message from queue A
    byte[] messageBytes = new byte[theMessage.getMessageLength()];
    theMessage.readFully(messageBytes);
    String messageText = new String(messageBytes);

    // Store the message to the logs in case of crash

    // Put the message in queue B
    queueB.put(theMessage);

  } catch (MQException e) {

    // Break the loop if we get an MQException
    // Hopefully, it is a reason code 2033 (out of messages)

  } catch (IOException e) {

    // Something went wrong reading the message

  }
}

Generally, if you want to keep track of messages read and written, you should use transactional reading/writing.

MQGetMessageOptions gmo = new MQGetMessageOptions();   
gmo.waitInterval = 1000;
gmo.options = MQGMO_WAIT;
gmo.options += MQGMO_FAIL_IF_QUIESCING;
gmo.options += MQGMO_SYNCPOINT;

MQPutMessageOptions pmo = new MQPutMessageOptions();
pmo.options += MQPMO_SYNCPOINT;

// create message instance
MQMessage message = new MQMessage();
message.correlationId = MQCI_NONE;
message.messageId = MQMI_NONE;

// read message
queueA.get(message, gmo);

// write message
queueB.put(message, pmo);

// commit transaction
qmgr.commit();

In that case, if transaction will not be committed, all read messages will return to the source queue and all written messages will disappear from target queues. It may be good idea to commit not every message, but every 10 or 100 depending on their amount.

If you're not going to use distributed transactions (eg saving some information from MQ messages to database), that would suffice. Otherwise I'd recommend to switch to JMS because of its better transaction support.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM