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

  • Stuck on how to handle my exceptions

    Hi,

    I've been stuck for a while on a simple case about how to handle exceptions correctly in my flows.
    Could somebody help me with that please ?

    Here is what I want to do :
    • Read a message from a JMS Queue in transaction (so no asynchronous flow possible)
    • Call a few transformers and service-activators (still within the JMS transaction)
    • Post the resulting message in another JMS Queue.
    • In case an exception occurs anywhere in this process, I want to catch the exception, log it and store the incoming message (in another JMS Queue for example). Then commit the transaction and process the next message.

    I thought of setting a ErrorHandler on the <message-driven-channel-adapter>, but even though the exception is catched and the ErrorHandler well executed, the exception is also thrown back, so the transaction is rollbacked ! Thus, the message never gets committed and is processed over and over...

    This seems quite a simple case, but no clue how to deal exceptions in this case... Any idea that could help me out?

    Thank you very much!

    Pierre

  • #2
    Ok, are you sending any reply message back to the sender, because if you do the jms:inbound-gateway has exception-mapper property, which allows you set InboundMessageMapper implementation converting Exception to a successful message. Would that help?

    Comment


    • #3
      Hi Oleg and thank you for your answer.
      Unfortunately, I'm not sending any reply message back to the sender.

      Comment


      • #4
        Just wanted to let you know that I am still looking into this, should get back to you shortly.

        Comment


        • #5
          Thank you Oleg, I appreciate.

          By the way, I was wondering something: Is it normal that, after the ErrorHandler is called, the exception is still thrown back? If an ErrorHandler is defined, is there really a point in having the exception thrown all the way back to the caller? Isn't it precisely why we defined an ErrorHandler?

          Comment


          • #6
            Pierre,

            You are right that an ErrorHandler on the MessageListener container should be able to suppress the Exceptions from being propagated.

            Can you provide more detail about the ErrorHandler implementation you are using and also how it's being configured?

            Thanks,
            Mark

            Comment


            • #7
              I have the same requirement, we are using AMQ DLQ strategy to handle all receiver exceptions, but ideally we want to be able to catch the exception and send it onto a an invalid message channel http://www.eaipatterns.com/InvalidMessageChannel.html and then use the SI exception router to kick in depending on the type of exception, but still allowing the underlying transaction to commit.


              I was sort of hoping it would have been supported as part of the following JIRA fixed https://jira.springframework.org/browse/INT-907

              Thanks

              Comment


              • #8
                You'll find below the smallest configuration to reproduce my case.

                Actually, it looks more like a Spring JMS problem than a Spring Integration one as the errorHandler is part of the class org.springframework.jms.listener.AbstractMessageLi stenerContainer

                That's the only way I found to handle my exceptions with Spring Integration in a synchronous flow (I know we have already discussed this subject before, but I still hope someday to see a more flexible way (per-endpoint strategy) to handle exceptions in SI :-)).

                Spring Context

                Code:
                <int-jms:message-driven-channel-adapter container="jmsListener" channel="channel1"  />
                
                <bean id="jmsListener" parent="queueListenerMce">
                	<property name="destinationName" value="MCEHoldingForexErrorQueue" />
                	<property name="sessionTransacted" value="true" />
                	<property name="errorHandler">
                		<bean class="com.sample.MyErrorHandler" />
                	</property>
                </bean>
                	
                <int:publish-subscribe-channel id="channel1" />
                
                <int-stream:stdout-channel-adapter channel="channel1" append-newline="true" />
                
                <int:service-activator input-channel="channel1" output-channel="nullChannel">
                	<bean class="com.sample.ExceptionThrower" />
                </int:service-activator>

                com.sample.ExceptionThrower

                Code:
                public class ExceptionThrower {
                	public void throwException(String ok) {
                		throw new RuntimeException("Oh oh...");
                	}
                }
                com.sample.MyErrorHandler

                Code:
                public class MyErrorHandler implements ErrorHandler {
                	@Override
                	public void handleError(Throwable arg0) {
                		System.out.println("Hey, the message failed!");
                	}
                }

                Comment


                • #9
                  I just want to clarify one thing...

                  Earlier you mentioned this:
                  even though the exception is catched and the ErrorHandler well executed, the exception is also thrown back, so the transaction is rollbacked !
                  Then, you mentioned this:
                  the ErrorHandler is called, the exception is still thrown back? If an ErrorHandler is defined, is there really a point in having the exception thrown all the way back to the caller?
                  I don't think the Exception is actually being *thrown back* anywhere. The rollback is triggered prior to the ErrorHandler being invoked, because if the Session is transactional it will always rollback for any Exception (JMSException or RuntimeException).

                  So, the first thing that I'd like to clarify is why you are using a transactional Session if you are *always* going to commit?

                  I've got a few other questions, but I want to take them one at a time

                  Thanks,
                  Mark

                  Comment


                  • #10
                    Good question.

                    We can't afford losing any message in case of a "crash" (if the JVM shuts down unexpectedly, if an OutOfMemoryError occurs, ...), so we need to ensure that the message has been posted on the second queue before committing the first one.

                    (Note: On the other hand, we can afford having duplicate messages, as we are able to identify them)

                    Next question?

                    Comment


                    • #11
                      Actually, before my next real question, I would like to ask if the comment I made about Exceptions being "thrown back" makes sense? I think you are just seeing the rollback behavior, correct? Otherwise, I need to understand what you meant by "thrown back".

                      Thanks,
                      Mark

                      Comment


                      • #12
                        You're right.
                        I was just seeing that my ErrorHandler was executed, and that the transaction was rollbacked, but no idea in what order.

                        Comment


                        • #13
                          Okay. So, my next question is... are the Exceptions expected from a certain component within the pipeline, or do you really expect that *un-caught* Exceptions might occur in a number of different places.

                          The reason I'm asking is that 2 ways to handle this could be 1) explicitly catch Exceptions where they are considered "non-fatal" and expected or 2) apply an AOP proxy to the component(s) that may propagate Exceptions.

                          Comment


                          • #14
                            I could identify four cases we have to deal with:

                            Case 1: Some exceptions are expected and can be catched (within the POJO class of a <service-activator> for example).
                            However, in case an exception occurs, we don't want the service-activator to return a valid result: the regular flow must end there and the message must be redirected to an "error-handling" flow. Knowing this, letting the exception propagate (instead of catching it) until a "ErrorHandler" catches it didn't seem such a bad idea.

                            Case 2: Some exceptions are expected but can't be catched because the POJO class of the service-activator belongs to an external library and is not modifiable.

                            Case 3: Some exceptions are expected but can't be catched because the endpoint is purely Spring Integration code. For instance, we can't catch an exception if the <int-xml:jaxb2-unmarshaller> fails because the XML is not correct.

                            Case 4: Unexpected exceptions. There are always cases we can't foresee before a Production use. We don't want the surprise of having a "looping" message in Production because we forgot to catch an Exception somewhere.

                            In all four cases, the exception is "fatal", the failing message has to exit its normal flow and should enter an "error-handling flow" (where it will be stored and an emailed for instance).

                            To sum up, all exceptions are considered "fatal" and have to be processed by what I call the "error-handling flow" (which we would like sometimes to be different depending on the exceptions and in which endpoint the exception occurred, but that's just bonus ).

                            --

                            I'm not sure to understand how to apply your suggestions to my use cases:

                            (1): If all the exceptions that occur are considered 'fatal', I guess that solution (1) doesn't apply?
                            (2): Is it possible to apply an AOP proxy to an endpoint such as <message-driven-channel-adapter> (which would then catch all uncaught and unexpected exceptions of my flow -- would be nice!) or <xml:unmarshalling-transformer> (which would then catch only the exceptions that occur in that transformation)?
                            If so, that would solve it all (at the price of a few AOP Proxy, but this sounds reasonable).

                            [EDIT]
                            Actually, I'm not sure that it would solve it all... If the AOP Proxy can catch the exception and send the message on the "error-handling flow", what will happen on the regular flow once the Proxy has done its job? I guess, a valid output is still expected so the flow can continue... :-/
                            Last edited by plecesne; Nov 5th, 2010, 09:46 AM.

                            Comment


                            • #15
                              Hi Mark, Oleg,

                              Does my answer make sense for you?
                              Do you have any idea about how I could handle those 4 types of exceptions regarding my constraints (basically, having a synchronous flow and a transactional context)?

                              Thank you!

                              Comment

                              Working...
                              X