Sunday, November 8, 2015

Practical Tips and Tricks with Spring Integration (part one) attempted transcription of webinar

Learning Spring Integration by looking at  various messaging system XML configurations, in particular ones that make heavy usage of the namespace features, can be instructive but at the same time frustrating because one cannot easily develop a solid intuition about how the internals of the messaging system works. Looking at the underlying implementation often helps but can be somewhat discouraging as well because one often gets the feeling that one is trying to look at an elephant through a key hole because understanding code can be difficult if one doesn't know the intentions and thoughts of the developers who wrote the code.

What follows below are notes, or an attempted transcription, of the first few minutes of a Spring Pivotal Webinar from Oleg Zhurakousky called "Practical Tips and Tricks with Spring Integration", which I found incredibly helpful and full of amazing insights. Spring already has a lot of great documentation and probably doesn't need anymore, especially from someone who is an outsider, but while listening to the webinar for the first time, I realized that every sentence that Oleg said was packed with more meaning than I could absorb in real time. So I replayed it several hundred times and came up with the following crude copy of his explanations.

Error Handling related to messaging systems. 
2:42 
Message systems like any other system can produce errors. Very often the process of handling messages relies on messaging itself. The first example demonstrates this by showing how an error channel can be defined on the components, gateway and inbound adapters, which serve as entry points into a messaging flow.

At this point one should be clear of the distinction between components which serve as entry points into messaging flows, gateway and channel-adapters, and components which serve as message flow handlers within a flow; namely service-activators, transformers, filters, etc.

3:23 
A question which is often asked is: why isn’t there an error channel attribute on message flow handlers? An analogy which helps to understand this is that of exception handling where a messaging flow is equivalent to a Java block of code encapsulated by a try-catch block, where the try serves as an entry point into the block of code and each line of code within the try-catch is analogous to a message handler. An exception can happen anywhere within the try-catch block and when it happens, the "try" then delegates the flow to the catch block, which is essentially the error channel. Giving each message handler its own error channel attribute, or its own error handling routine, would be like supplying each statement within a try-catch block with its own try-catch, which would only complicate the picture.

Essentially components that serve as entry points into messaging flows are like try-catch blocks and also serve as components, which mark the boundaries or scopes of the messaging follows.  Error handling blocks of try-catch statements can be arranged right after each other, sequentially, or nested within each other to produce different behaviors. This can also be accomplished in a message flows as well and later it will be shown how to partition or segment message flows to accomplish that which we accomplished with traditional try-catch error handling.

4:56 Sample one.
The first configuration, sample, has a messaging gateway, which is our ErrorDemoGateway, and when we invoke the method on the gateway, the gateway sends the message to the inputChannel, which is a splitter, which splits the message and sends it to the processingChannel.  From the processChannel, the message is going to be processed by the filter and the filter is going to validate that the message's payload's length is greater than four. If it is, then it will be allowed to proceed and if not, it will raise an exception because of the attribute “throw-exception-on-rejection” is set to true. The successfully validated message will then go to the loggingChannel, which is basically a logging-channel-adapter, which will log the massage.

The explicit definition of the channel loggingChannel can be removed because it will be automatically created. Right now, our gateway does not define an error logging channel. So when we execute the code, we shall see that the exception gets caught in the caller’s code, which called the interface’s method.

To avoid that the caller has to deal with the exception and instead be gracefully informed that an error has occurred, we define a channel called “processErrorChannel” and point the gateway’s error-channel attribute to it. When an exception occurs the gateway will see that the error-channel attribute is explicitly define and will send the error message to the error channel to give the caller another chance to correct the message. In the transformer, which is subscribed to the error channel, the payload of the original message will be wrapped in hash tags to indicate that the message was in error.

Looking at the caller code, which gets the gateway from the application context and which calls its method with two strings, one which is too short, we can see from the logging output that one strings passes the filter and the other not by the presence of hash marks.
The exception is no longer propagated back to the caller as it was without the explicit definition of the error channel on the gateway.

8:56 Sample 2
Enterprise Integration Patterns (I assume the speaker was referring to the book) identifies several components, which are state full by nature and which may depend on a predetermined amount of messages coming in before some action would be taken. For example, you might have a flow with an aggregator, which expects three messages but if an error happens in the upstream processing, then the required amount of messages will never reach the aggregator and it in turn will never release the received messages.

10:07
However, by handling the error via a message flow, it is possible to send the message or some message describing the error to the aggregator thus satisfying the release requirements.
In the example, the message gets sent and is split before being sent onto the filter, which will only pass one of the messages onto the aggregator. The other one will be filtered out. This means that the aggregator will be holding onto one message and waiting for the other one, which will never come.

10:43
The application is demonstrated before being fixed, whereby the rejection exception is thrown but the application keeps running. The speaker then shows, using jconsole, that the aggregator has only processed one message. The application is then fixed by setting the gateway’s error-channel attribute to errorChannel.

13:34 Flow Segmentation and Flow Partitioning
Using the same try-catch analogy as we discussed at the beginning let’s look at a slightly different error handling requirement. Depending on the handler that generated the exception or result in the exception you may not want the exception to propagate back to the original entry point of the entire flow.

Using Java’s try-catch analogy it is as if you want to wrap part of the flow downstream in its own try-catch block. Basically, you want to create an independent flow partition or segment and to do this we shall use a technique that allows us to introduce a sub entry point within an existing messaging flow.

We do this by introducing a messaging gateway downstream, which is invoked by a service activator. So let’s look at how we do that. We do it actually quite simply. We have a gateway just like we had before (now called segmentOneGateway). We already have an error channel. This gateway, segmentOneGateway, identifies a request channel called segmentOneChannel, which has a subscriber that is a service activator, which is bootstrapped with a reference to a bean called segmentOne. The bean segementOne is actually another gateway, which is defined further downstream. The only difference here is that this gateway does not identify a service interface as it is no longer needed because it’s bootstrapped with the default interface. Once the service activator invokes the gateway segmentOne, it is as if someone else invoked a gateway and entered a sub partition or another messaging flow. This new flow is actually sitting within some parent messaging flow. We now have a service activator, which is being invoked by the second gateway, segmentOne, and if its throw and exception the exception will be send to it invoking gateway error channel, namely.

TBC
https://youtu.be/RY6dNUL8k6o?t=18