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/