On 8/7/07, James Strachan <[EMAIL PROTECTED]> wrote:
> On 8/7/07, Neil Thorne <[EMAIL PROTECTED]> wrote:
> >
> > Hi Neil
> > Hi James thanks for the quick reply.
> >
> > >> a) a system exception gets thrown. A system exception indicates an
> > >> infrastructure problem that will be fixed ASAP as it is essential to the
> > >> correct functioning of the system as a whole. eg. jdbc connection failed,
> > >> remote system is down etc. If a system exception is thrown then that
> > >> operation should be continually retried until it is successful.
> > >>
> > >> b) a business exception is thrown. A business exception indicates that
> > >> there
> > >> was a problem with the request itself. It should not be retried (at least
> > >> not until the problem has been resolved). The message should be moved
> > >> onto a
> > >> hospital queue where it can be inspected, changed and retried after
> > >> possible
> > >> manual intervention.
> >
> > > BTW how can you tell the difference between a) and b)? Are there
> > > certain base exception types you can use?
> >
> > Yes I can. Although our applications can throw quite a few different
> > exceptions, so far in terms of routing we only need these two base types. We
> > have translators that convert the original exception to one of these types.
>
> Ah cool. I was wondering; rather like the Type Converter stuff....
> http://activemq.apache.org/camel/type-converter.html
>
> Do we need a simple little framework where we can easily mark
> exception types as being 'system exceptions' or 'business exceptions';
> so the error handler can do the right thing by default without
> explicit configuration in the DSL?
>
> e.g. for code you own, we could add an @BusinessException or
> @SystemException annotation. The annotation could even configure the
> retry count/timeout to be specified on a per exception basis.
>
> For code that we don't own, we could add some kinda
> META-INF/services/org/apache/camel/BusinessExceptions file that lists
> the base classes of all the business level exceptions (or system
> exceptions etc).
>
> Am thinking btw that it might be easier to mark just the business
> level exceptions; as the system exceptions tend to be more diverse &
> harder to enumerate.
>
> If we could know using the 'ExceptionRepository' what exceptions are
> which, then we can know whether or not to retry etc.
>
> Am even thinking, maybe we could attach different error handling to
> certain types of exception. e.g. if we can ever really detect a true
> database deadlock (which is getting harder these days due to exception
> wrapping etc) - we might want to increase the retry counts etc.
>
>
> > >> What is the simplest way to achieve this with camel? Currently I can only
> > >> see an errorHandler which assumes you want to dump messages that cannot
> > >> be
> > >> processed to an error endpoint.
> >
> > >An ErrorHandler could do anything - e.g. based on the type of
> > >exception it could decide whether or not to retry (if at all) etc.
> >
> > >The default implementation is DeadLetterChannelErrorHandler, which
> > >assumes n-retries with optional backoff delays - before sending to a
> > >'dead letter' endpoint, which is kinda like your hospital queue
> >
> > Okay I can write my own implementation.
>
> Please let us know how you get on - as I'd love something like this to
> be in the core of Camel.
>
> e.g. maybe we can patch the default DeadLetterChannelErrorHandler to
> use some kinda pluggable strategy to determine if an exception is a
> business level exception (and so the retry logic is not used etc)
>
>
> > We're using the Java DSL style of
> > configuration.
> >
> > I'd need to set two different retry strategies depending on the type of
> > exception.
> >
> > from("direct:a").errorHandler().filter(
> > type.isEqualTo("com.acme.BusinessException").
> > maximumRedeliveries(0).to("direct:business.errors")
> > ).errorHandler().filter(
> > type.isEqualTo("com.acme.SystemException").
> > maximumRedeliveries(-1).useExponentialBackOff()
> > ).to("direct:b");
>
> Looks good :)
>
>
> > Without explicit DSL support I'm wondering about the custom ErrorHandler
> > impl, and what the current DSL
> > would have to look like. I don't have to specify any endpoint for the
> > ErrorHandler right?
>
> The current default error handler uses any-old-processor as the dead
> letter queue; so you could configure separate endpoints depending on a
> system or business exception; but maybe you just wanna change the
> properties (retry count / backoff times etc) and leave the default
> behaviour...
>
>
> > In that case I could just manually post messages to the "business exception"
> > endpoint if the exception type matches using a spring configured proxy, or
> > otherwise just go into an infinite loop. I'll read the source for
> > DefaultErrorHandler to get a better understanding of the ErrorHandlers in
> > general.
>
> I'm even wondering if the DSL should have exception handling as a core
> feature. I guess we can either, add routing/filtering inside a
> specific error handler; or we could add explicit error-handling
> routing constructs.
>
>
> > >Firstly you can customize the errorHandler on a set of routes, or a
> > >specific route, or within the processing of a route. So if you had
> > >your own idea errorHandler implementation you could use it wherever
> > >you like
> >
> > >Currently there's no 'exception-type-based error handler'
> > >implementation; but it should be easy to add such a thing. e.g. we
> > >could add a Set<Class> property to the DeadLetterChannel for
> > >exceptions which should not be retried maybe?
> >
> >
> > > If I could then I suppose I could move business exceptions immediately to
> > > the hospital queue (with a retry count of zero).
> > >
> > > I could also bind a different error handler with an infinite retry count
> > > (-1?).
> >
> > >Yeah - I've been pondering similar things. I'm wondering if we should
> > >have some kinda version of the Content Based Router that uses a
> > >similar notation to try/catch/finally; where known business related
> > >exceptions are caught and the message forwarded to a 'business logic
> > >failed' type endpoint, otherwise system exceptions (which are way more
> > >random and harder to catch all) filter up to the default errorHandler
> > >- such as for retrying & dead letter channels etc.
> >
> > >e.g. in XML I was pondering something like
> >
> > <try>
> >   <!-- do some stuff here which may throw exceptions -->
> >
> >   <catch error="org.foo.bar.SomeBusinessException">
> >     <!-- for business level exceptions, send to some reject queue -->
> >     <to uri="activemq:myRejections'/>
> >   </catch>
> >
> >   <!-- any other system exceptions cause the error handler to retry n-times
> > -->
> > </try>
> >
> > >Thoughts?
> >
> > yes this would also seem to do the trick. Would this style be supported in
> > the Java DSL?
>
> Ideally yes - both Java and XML
>
>
> > I'm just going into the office. I'll be back in an hour or so. Hopefully the
> > DSL above clarifies what we need.
>
> Yes thanks! I've just woke up - a tad early - so need a bit more
> coffee to ponder this a bit more; as I think there's a few ways we
> could go, am currently not sure the best way (or if we should do all
> of them :)
>
> * we could have some kinda metadata registry thing, like the Type
> Converter, to indicate what exceptions are really system exceptions
> versus business exceptions, so that the default error handler can just
> do the right thing (e.g. have default, or customizable retry counts by
> type (business v system) or even customize by a specific exception
> type etc
>
> * we could add routing inside the error handler as you suggest
>
> * we could add some kinda try/catch type construct to the DSL so that
> the DSL itself can describe the routing & handling of exceptions
>
> The last 2 are kinda similar in some ways. I guess each have strengths
> and weaknesses; I kinda like simplifying the DSL as much as possible
> and having things do the right thing without needing much explicit
> coding (rather like the type conversion stuff); but sometimes making
> the DSL totally explicit (e.g. in terms of error handling or type
> conversion) can be useful.
>
> Let me have more coffee & I'll get back to you :)

I've just added to trunk a little try/catch style routing DSL.

In Java we can't use try/catch/finally words so I've initially gone with this

  from("direct:start").
          tryBlock().
              process(validator).
              to("mock:valid").
          handle(ValidationException.class).to("mock:invalid");

which is maybe not the easiest thing to read; but tryBlock / handle is
a replacement for try/catch. (Maybe tryBlock/catchBlock is more
consistent?). Any name suggestions most welcome! (Its often the
hardest part of programming, coming up with good names for things).

In XML its a little easier on the eye. e.g. here's a validation test
case to ensure that messages are delivered to different endpoints
depending on whether they are valid or not...
https://svn.apache.org/repos/asf/activemq/camel/trunk/components/camel-spring/src/test/resources/org/apache/camel/component/validator/camelContext.xml

In Java we could even use the real try/catch handling using an inline Processor

e.g.

        from("direct:start").process(new Processor() {
            public void process(Exchange exchange) throws Exception {
                try {
                    validator.process(exchange);

                    template.send("mock:valid", exchange);
                }
                catch (ValidationException e) {
                    template.send("mock:invalid", exchange);
                }
            }
        });

Thoughts?

-- 
James
-------
http://macstrac.blogspot.com/

Reply via email to