Announcement Announcement Module
Collapse
No announcement yet.
How to re-queue a message pulled from exception Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to re-queue a message pulled from exception

    I'm new to Spring Integration and have a working flow, but now I'm working on handling errors.

    I am catching errors using an exception-type-router then sending those through a Control Bus to stop polling and re-queue the error message.

    I thought I could just send the message I got from the Exception back to the Message Channel, which is a queue, but it doesn't work.
    Code:
    notificationQueue.send(MessageBuilder.withPayload(messageAtFailure.getPayload()).build());
    When I monitor it using jmx, I see that the message is sent, but it never gets queued.
    How can I re-queue the message?

  • #2
    First of all you should try to avoid using framework components in your services; just code to POJOs and let the framework take care of the messaging.

    Error handling is one exception, although in many cases you can avoid it there too, using transformers, header enrichers etc.

    Further, it's usually better for questions like this if you show pertinent parts of your configuration.

    The actual error handling really depends on the structure of your flow. Typically, if the inbound entry point is a gateway, you only get one shot at dealing with the exception, unless you add additional error handling to your flow.

    The ErrorMessage payload is a MessagingException (the ETR drills down through the cause tree to find the most specific exception for which there is a mapping).

    The MessagingException has two properties 'failedMessage' (the original message) and 'cause'.So typically, for use cases like yours, people extract the failedMessage (with a transormer) and send it to some recovery flow. However, as I said, there are other considerations, depending on the overall flow configuration.

    Another technique for use cases like this is to wrap your service in a retry advice; perhaps using the retry recoverer to send the message to a delayer, if you want to free up threads.

    If you can describe your use case further (provide a general picture of the flow), I am sure someone can guide you.

    Comment


    • #3
      Gary, thanks for your comments.

      My attempt to put a message back on the queue was called from error-handling code. Here are some artifacts from the project that may help explain better what I want(ed) to do.

      Integration Graph:
      Attachment


      Error-handling Service Activator code:
      Code:
      @Component
      public class ControlBus {
          @Autowired MessageChannel controlChannel;
          @Autowired MessageChannel resetReadForSendingChannel;
          @Autowired QueueChannel notificationQueue;
          @Autowired MessageChannel otherExceptionErrorChannel;
          
          @SuppressWarnings("rawtypes")
          public void stopPollersAndReSubmit(Exception e) {
              Message stopPollingForNewChanges = MessageBuilder.withPayload("@jdbcInboundChannelAdapter.stop()").build();
              Message stopRecipRouter = MessageBuilder.withPayload("@recipRouter.stop()").build();
              controlChannel.send(stopPollingForNewChanges);
              controlChannel.send(stopRecipRouter);
              
              //fish out the original message and put it back on the notificationQueue
              Message messageAtFailure = null;
              MessagingException me = null;
              
              if (e instanceof MessagingException) {
                  me = (MessagingException)e;
              } else if (e instanceof TransactionSystemException) {
                  TransactionSystemException tse = (TransactionSystemException)e;
                  me = (MessagingException)tse.getApplicationException();
              } else { // didn't get the kind of exception based on a Jms or Jdbc error, so route to otherException
                  StringBuilder sb = new StringBuilder();
                  sb.append("Received unexpected error while handling a Jms or Jdbc error:\n\n");
                  sb.append("Exception.getMessage(): " + e.getMessage() + "");
                  StringWriter sw = new StringWriter();
                  e.printStackTrace(new PrintWriter(sw));
                  sb.append(sw.toString());
                  otherExceptionErrorChannel.send(MessageBuilder.withPayload(sb.toString()).build());
              }
              
              if (me != null) {
                  messageAtFailure = me.getFailedMessage();
                  // want to re-queue failed message by sending back, but ...
                  notificationQueue.send(MessageBuilder.withPayload(messageAtFailure.getPayload()).build());
                  
                  // ... had to send to a jdbc-outbound-channel adpater to update a field so message will be re-read
                  resetReadForSendingChannel.send(MessageBuilder.withPayload(messageAtFailure.getPayload()).build());
              }
      
          }
      }
      To be sure the error-handling part needs improvement, and I probably should do less in terms of routing to different channels in the code. The gist of the code, however, is that if the JMS broker is down, I want to stop the polling in the flow and requeue the message back to the notificationQueue so when the polling resumes it will be picked up.

      The last section of the code shows where I attempted to resend the message, which was in fact re-'sent', but not re-queued (as shown by jmx), and hence not reprocessed. So the alternative solution I came up with updates the database so it would be picked up again at the start of the whole process.

      So, after all that, is it possible to get a message back on the queue programmatically?
      Attached Files

      Comment


      • #4
        You should be able to put it back on the queue without any problems (assuming your notification gateway service-interface returns void and is not expecting a reply). It will be picked up by the router when you restart it.

        However, it is probably safer to do what you are doing because messages in the notification queue will be lost anyway if the server goes down. Using a queue channel here (regardless of failures) is prone to losing messages when the server fails.

        As a general rule, the best way to debug these questions is to turn on DEBUG logging for org.springframework.integration and trace the messages (via the channel pre/post Send/Receive etc log messages).

        Comment

        Working...
        X