Added discussion of error handling (INT-457).

This commit is contained in:
Mark Fisher
2008-11-26 05:52:44 +00:00
parent 9f61208de4
commit 2e3a0487e0

View File

@@ -91,8 +91,8 @@
</para>
</section>
<section id="namespace-messagebus">
<title>Configuring the Message Bus</title>
<section id="namespace-taskscheduler">
<title>Configuring the Task Scheduler</title>
<para>
In Spring Integration, the ApplicationContext plays the central role of a Message Bus, and there are only a
couple configuration options to be aware of. First, you may want to control the central TaskScheduler instance.
@@ -108,20 +108,61 @@
When the endpoints are concurrency-enabled with their own 'taskExecutor' reference, the invocation of the
handling methods will happen within that executor's thread pool and not the main scheduler pool. However,
when no task-executor is provided for an endpoint's poller, it will be invoked in the dispatcher's thread
(with the exception of subscribable channels where the subscribers will be invoked directly).
(with the exception of subscribable channels where the subscribers will be invoked directly). The next
section will describe what happens if Exceptions occur within the asynchronous invocations.
</para>
</section>
<section id="namespace-errorhandler">
<title>Error Handling</title>
<para>
As described in the overview at the very beginning of this manual, one of the main motivations behind a
Message-oriented framework like Spring Integration is to promote loose-coupling between components. The
Message Channel plays an important role in that producers and consumers do not have to know about each
other. However, the advantages also have some drawbacks. Some things become more complicated in a very
loosely coupled environment, and one example is error handling.
</para>
<para>
The Message Bus supports error handling for its components in the form of a configurable error channel,
and it will first check for a channel bean named "errorChannel" within the context:
When sending a Message to a channel, the component that ultimately handles that Message may or may not
be operating within the same thread as the sender. If using a simple default DirectChannel (with the
&lt;channel&gt; element that has no &lt;queue&gt; sub-element), the handling will be in the same thread.
In that case, if an Exception is thrown, it will be catch-able by the sender (or it may propagate past
the sender if it is an uncaught RuntimeException). So far, everything is fine. This is the same behavior
as an Exception-throwing operation in a normal call stack. However, when adding the asynchronous aspect,
things become much more complicated. For instance, if the 'channel' element <emphasis>does</emphasis>
provide a 'queue' sub-element, then the component that handles the Message <emphasis>will</emphasis> be
operating in a different thread than the sender. The sender may have dropped the Message and moved on to
other things. There is no way for the Exception to be thrown directly back to that sender using standard
Exception throwing techniques. Instead, to handle errors for asynchronous processes requires an
asynchronous error-handling mechanism as well.
</para>
<para>
Spring Integration supports error handling for its components by publishing errors to a Message Channel.
Specifically, the Exception will become the payload of a Spring Integration Message. That Message will
then be sent to a Message Channel that is resolved in a way that is very similar to the 'replyChannel'
resolution. First, if the request Message being handled at the time the Exception occurred contains
an 'errorChannel' header (the header name is defined in the constant: MessageHeaders.ERROR_CHANNEL),
the ErrorMessage will be sent to that channel. Otherwise, the error handler will send to a "global"
channel whose bean name is "errorChannel" (this is also defined as a constant:
IntegrationContextUtils.ERROR_CHANNEL_BEAN_NAME).
</para>
<para>
Whenever relying on Spring Integration's XML namespace support, a default "errorChannel" bean will be
created behind the scenes. However, you can just as easily define your own if you want to control the
settings.
<programlisting language="xml"><![CDATA[ <channel id="errorChannel" capacity="500"/>]]></programlisting>
When exceptions occur in a scheduled poller task's execution, those exceptions will be wrapped in
</para>
<para>
The most important thing to understand here is that the Messaging-based error handling will only apply
to Exceptions that are thrown by a Spring Integration task that is executing within a TaskExecutor.
This does <emphasis>not</emphasis> apply to Exceptions thrown by a handler that is operating within
the same thread as the sender (e.g. through a DirectChannel as described above). However, when
Exceptions occur in a scheduled poller task's execution, those exceptions will be wrapped in
<classname>ErrorMessages</classname> and sent to the 'errorChannel' by default. To enable global error
handling, simply register a handler on that channel. For example, you can configure Spring Integration's
<classname>ErrorMessageExceptionTypeRouter</classname> as the handler of an endpoint that is subscribed to the
'errorChannel'. That router can then spread the error messages across multiple channels based on
<classname>Exception</classname> type. However, since most of the errors will already have been wrapped in
<classname>MessageDeliveryException</classname> or <classname>MessageHandlingException</classname>,
the <classname>ErrorMessageExceptionTypeRouter</classname> is typically a better option.
<classname>Exception</classname> type.
</para>
</section>