Announcement Announcement Module
Collapse
No announcement yet.
Stuck on how to handle my exceptions Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    We are still debating it stand by

    Comment


    • #17
      We had a few thoughts about it in my team too and we think having found a (temporary?) solution:

      Defining our own TaskExecutor, which is actually a mix of the existing SyncTaskExecutor and ErrorHandlingTaskExecutor : a TaskExecutor that would just run the task synchronously and send any exceptions to an errorHandler.

      Something that will probably look like the following class:

      Code:
      public class SyncErrorHandlingTaskExecutor extends SyncTaskExecutor {
      
      	private ErrorHandler errorHandler;
      	
      	@Override
      	public void execute(Runnable task) {
      		Assert.notNull(task, "Runnable must not be null");
      		try {
      			task.run();
      		} catch (Exception e) {
      			getErrorHandler().handleError(e);
      		}
      	}
      
      	public ErrorHandler getErrorHandler() {
      		return errorHandler;
      	}
      
      	public void setErrorHandler(ErrorHandler errorHandler) {
      		this.errorHandler = errorHandler;
      	}
      
      }
      Then, any channel could have this task executor set to its dispatcher.
      Any channel could also have a different ErrorHandler if needed.
      --

      Mark, Oleg,
      What do you think about this solution? Do you see any obvious drawback or major issue?

      Comment


      • #18
        After lengthy discussions, we have created the following issue:https://jira.springsource.org/browse/INT-1623

        You will see that it's a slightly different approach to anything we've had before. We will be adding the "error-channel" option to gateways as well as "inbound-channel-adapter" elements. The description there should be relevant in both cases, except for the use-case where a valid reply Message is generated from the Exception.

        Please let us know if that issue sounds like it will address your needs. You can comment directly in JIRA.

        Thanks,
        Mark

        Comment


        • #19
          Sounds good!

          I have a few questions though. (I didn't want to post them on the JIRA if they are not relevant).

          1. Will it be the MessagingException that will be sent on the error-channel?

          2. Let's say I have the following flow:
          Code:
          Inbound CA --> SA #1 --> SA #2 --> SA #3 --> Outbound CA
          
          CA : Channel Adapter
          SA : Service Activator
          --> : Direct Channel
          Now, the behaviour that I want is:
          - If an exception is thrown within SA #1 or SA #2, I want to redirect the failed message to errorChannel and handle that properly (store the message, and send an email, for instance)
          - If an exception is thrown within SA #3 or Outbound CA due to a ConnectException or RemoteException, I want to retry 1000 times (with a delay of 10s between each try) and if it still fails, redirect the message to an errorChannel.


          Is it a case that will be handled with the RetryInterceptor (JIRA 343) or is it something that could be added to this new "error-channel" attribute feature? Or is it already something possible?
          If this case could be handled, this would make it the perfect "error handling kit" as I believe most cases could then be handled.

          Sorry for the long thread, and thank you for caring

          Pierre

          Comment


          • #20
            Yes, INT-343 would be getting into that type of retry logic. In the meantime, I would recommend just adding a custom component within the pipeline that does that (you can use another service-activator I guess).

            The case that we are trying to address is really more of a "catch-all" at the entry point, so it would receive the errors in case your custom retry handler fails even after all retries.

            The intention is to provide something analogous to the exception mappings that one configures in web.xml for a Servlet environment (again, a "catch-all"... or "last chance" mechanism for handling errors).

            Do you think this will be sufficient for now? The custom retry handler should be replaceable once we implement support for that (most likely in version 2.1).

            -Mark

            Comment


            • #21
              Yes, that's perfect for now.
              Thanks a lot, Mark.

              Comment


              • #22
                Hi Pierre,
                This is exactly what iam doing now and i is going into production on Jan 1st.
                I am using Websphere SI bus as default JMSrovider and using Spring integration 2.0.0.RC1 for my standalone consumer app.

                I am using Message driven channel adapter.
                Logic:
                1) Receive a message
                2) Process the message and do a http Post to Our customer Url.
                3) If step 2 fails, throw an exception. This way the message is retained in my JMS provider. In JMs provider there is a setting for On exception to block it for xxx millisecs. I am blocking it for 30 minutes before it is sent to My Standalone spring integration app.

                I am using deliveryCount in the message header as my retry count for my application logic. If retry fails for 6th time, i redirect the message to a different Queue destination on websphere SI Bus for further processing.

                so, you could do that, if your jms provider gives you the option for on exception handling.
                Hope this helps.
                --sri
                Originally posted by plecesne View Post
                Sounds good!

                I have a few questions though. (I didn't want to post them on the JIRA if they are not relevant).

                1. Will it be the MessagingException that will be sent on the error-channel?

                2. Let's say I have the following flow:
                Code:
                Inbound CA --> SA #1 --> SA #2 --> SA #3 --> Outbound CA
                
                CA : Channel Adapter
                SA : Service Activator
                --> : Direct Channel
                Now, the behaviour that I want is:
                - If an exception is thrown within SA #1 or SA #2, I want to redirect the failed message to errorChannel and handle that properly (store the message, and send an email, for instance)
                - If an exception is thrown within SA #3 or Outbound CA due to a ConnectException or RemoteException, I want to retry 1000 times (with a delay of 10s between each try) and if it still fails, redirect the message to an errorChannel.


                Is it a case that will be handled with the RetryInterceptor (JIRA 343) or is it something that could be added to this new "error-channel" attribute feature? Or is it already something possible?
                If this case could be handled, this would make it the perfect "error handling kit" as I believe most cases could then be handled.

                Sorry for the long thread, and thank you for caring

                Pierre

                Comment


                • #23
                  Hi Sri and thank you for your help.

                  I'm not sure if my JMS Provider has such options, but I will check as these sounds as interesting options.

                  The retry system is interesting in your example, but this solution is still not good enough for my use cases:
                  Let's take my example again (In-CA, SA#1, SA#2, ...) and let's say that the exception is always thrown in SA#2 (due to a disconnected remote partner), and let's say that SA#1 generates a unique ID: as the retry logic is located in the JMS Provider, if I retry 5 times, I will go through SA#1 five times and thus generate five unique ID for the same message... If I retry 10000 times, I will then waste 10000 unique ID.
                  That's why I need a retry system located at SA#2 and not at the beginning of my flow. I really hope that INT-343 will be able to solve this case.

                  Thank you anyway for sharing your tips.

                  Pierre

                  Comment


                  • #24
                    Ah, I understand it now.
                    did you look at Delayer component? You can place a delayer after SA#2 and retry that as many times as you want.

                    --sri
                    Originally posted by plecesne View Post
                    Hi Sri and thank you for your help.

                    I'm not sure if my JMS Provider has such options, but I will check as these sounds as interesting options.

                    The retry system is interesting in your example, but this solution is still not good enough for my use cases:
                    Let's take my example again (In-CA, SA#1, SA#2, ...) and let's say that the exception is always thrown in SA#2 (due to a disconnected remote partner), and let's say that SA#1 generates a unique ID: as the retry logic is located in the JMS Provider, if I retry 5 times, I will go through SA#1 five times and thus generate five unique ID for the same message... If I retry 10000 times, I will then waste 10000 unique ID.
                    That's why I need a retry system located at SA#2 and not at the beginning of my flow. I really hope that INT-343 will be able to solve this case.

                    Thank you anyway for sharing your tips.

                    Pierre

                    Comment


                    • #25
                      Errr... I'm not sure how that would work.

                      I only want to retry when an exception occurs. If an exception occurs in SA#2, I won't reach anything that is placed after SA#2... And if no exception occurs in SA#2, I don't want a delay or any retry.
                      Moreover, the delayer only adds a delay, there is no retry logic within this component.

                      If you had an idea in mind, could you be more specific? I think I didn't get it properly...

                      Comment


                      • #26
                        Not sure where you want to implement the retry logic, but here is the algorithm.

                        In the service Activator, you want to implement the retry logic, inject MessagingTemplate object and a Channel reference (Say delayerChannel).

                        Once you catch the exception, Create a copy of the failed message and increment retryLimit header value. (This is a custom header you need to add for every message from start of the flow.). Using MessagingTemplate send this new message to delayerChannel. Once it is on the delayerChannel, it will go through delayer element, it will be delayed for xxx ms and then will be send back to your Service Activator for resending.

                        This is little over engineering for retry logic, but will work.
                        Key elements in this are, retryLimit custom header and creating a new copy of the failed message for every failed attempt and incrementing the retryLimit header value.
                        Hope this is clear.
                        --sri


                        Originally posted by plecesne View Post
                        Errr... I'm not sure how that would work.

                        I only want to retry when an exception occurs. If an exception occurs in SA#2, I won't reach anything that is placed after SA#2... And if no exception occurs in SA#2, I don't want a delay or any retry.
                        Moreover, the delayer only adds a delay, there is no retry logic within this component.

                        If you had an idea in mind, could you be more specific? I think I didn't get it properly...

                        Comment


                        • #27
                          Oh now I see. Well, indeed, this would work. With quite a big dependence to SI API, but it would probably work
                          Sounds a bit too intrusive to me, but thank you for the advice, sri!

                          Comment


                          • #28
                            If your jms provider has the on Exception functionality, you can send all failed messages to a new destination and then receive the messages from the same destination for all failed messages using another Inbound adapter,
                            --sri
                            Originally posted by plecesne View Post
                            Oh now I see. Well, indeed, this would work. With quite a big dependence to SI API, but it would probably work
                            Sounds a bit too intrusive to me, but thank you for the advice, sri!

                            Comment


                            • #29
                              This does seem to be a Spring JMS issue really, but Spring Integration adds a layer of smarts on top of that, so there might be some hooks you can use. To prevent the rollback you need to catch the exception and deal with it in the MessageListener, which in this case is the downstream message flow.

                              Spring Integration sensibly doesn't provide an exception handling strategy for synchronous flows - it's much easier to handle them in the calling thread. The problem here is that the calling thread belongs to the MessageListenerContainer, deep in Spring JMS.

                              You could start by looking at customizing the dispatcher for the downstream channel. By default it does catch exceptions and tries to deliver the message to other subscribers (see UnicastingDispatcher). In your case you want the fallback subscriber to get not only the message but the exception as well - you can do that by implementing an alternate form of the dispatcher in a few lines probably.

                              Or you could put a special service activator downstream of the message listener that just delegates to a gateway, pushing the message on downstream but taking control of the calling thread, and allowing you to catch exceptions and handle them.

                              Or you could add an AOP interceptor to the downstream Channel.send() and do the same thing. (This is likely to be the approach we take in Spring Integration 2.1 to add declarative retry and recovery to message flows generally.)

                              Comment


                              • #30
                                I am actually using special service activator downstream and also ResponseHandler for HttpRequestMessageHandler (INT-1587) to get the retry functionality and some exception handling.

                                Yes, you are right, this is JMS issue and we need handle of calling thread and or Exception handling mechanish at the begining of the flow. This way we can handle exceptions and account for the messages.
                                Thanks
                                sri

                                Originally posted by Dave Syer View Post
                                This does seem to be a Spring JMS issue really, but Spring Integration adds a layer of smarts on top of that, so there might be some hooks you can use. To prevent the rollback you need to catch the exception and deal with it in the MessageListener, which in this case is the downstream message flow.

                                Spring Integration sensibly doesn't provide an exception handling strategy for synchronous flows - it's much easier to handle them in the calling thread. The problem here is that the calling thread belongs to the MessageListenerContainer, deep in Spring JMS.

                                You could start by looking at customizing the dispatcher for the downstream channel. By default it does catch exceptions and tries to deliver the message to other subscribers (see UnicastingDispatcher). In your case you want the fallback subscriber to get not only the message but the exception as well - you can do that by implementing an alternate form of the dispatcher in a few lines probably.

                                Or you could put a special service activator downstream of the message listener that just delegates to a gateway, pushing the message on downstream but taking control of the calling thread, and allowing you to catch exceptions and handle them.

                                Or you could add an AOP interceptor to the downstream Channel.send() and do the same thing. (This is likely to be the approach we take in Spring Integration 2.1 to add declarative retry and recovery to message flows generally.)

                                Comment

                                Working...
                                X