Camel主要支持以下几种ErrorHandler,Camel 默认预置 DefaultErrorHandler。
- DefaultErrorHandler
- DeadLetterChannel
- TransactionErrorHandler
1. 实现原理
对每一个Camel路由,在节点与节点之间都包含一个channel,channel主要用于运行态的监控和路由控制。
from("direct:newOrder")
.bean("orderService, "validate")
.bean("orderService, "store");
2. Handler简介
2.1 DefaultErrorHandler
DefaultErrorHandler的默认设置为:
- 不进行重试;
- 异常传回给调用者;
- 堆栈轨迹打印到日志文件中;
- exchange的路由历史打印到日志文件中;
默认情况下,异常发生后,handler会将异常信息作为exchange的属性存储起来,可以通过以下方法获取到异常信息:
final Exception exception = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
2.2 DeadLetterErrorHandler
DeadLetterErrorHandler与DefaultErrorHandler类似,不同点如下:
- DeadLetterErrorHandler是唯一一个将错误消息传递到错误队列的ErrorHandler。这个队列通常叫做 死信队列(dead letter queue)。
- 异常发送到死信队列,而非调用者
- 允许将原始消息发送到死信队列
异常发生时,进入死信队列的消息不是原始传入的消息,而是经过加工处理的消息,为了支持重试,你可能希望将原始消息存入死信队列。这时候可以通过useOriginalMessage
来实现。
errorHandler(deadLetterChannel("jms:queue:dead").useOriginalMessage());
2.3 TransactionErrorHandler
后续介绍……
3. 重试
Camel的重试是基于错误点的重试,而不是从整个路由开始进行重试。
3.1 示例
示例:自动重试5次,每次间隔10秒钟。
errorHandler(defaultErrorHandler()
.maximumRedeliveries(5)
.redeliveryDelay(10000));
示例2:自动重试2次,每次间隔1秒钟,日志级别WARN,不打印消息历史。
errorHandler(defaultErrorHandler()
.maximumRedeliveries(2)
.redeliveryDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.WARN)
.logExhaustedMessageHistory(false);
3.2 重试情况记录
exchange中与重试相关的Header。
Header | type | description |
---|---|---|
Exchange.REDELIVERY_COUNTER | int | The current delivery attempt |
Exchange.REDELIVERED | boolean | Whether this exchange is being redelivered |
Exchange.DELIVERY_EXHAUSTED | boolean | Whether this exchange has attempted (exhausted) all redeliveries and has still failed |
4. ErrorHandler的作用域
4.1 Context级别的ErrorHandler
errorHandler(defaultErrorHandler()
// enable async redelivery mode (pay attention to thread names in console output)
.asyncDelayedRedelivery()
.maximumRedeliveries(2)
.redeliveryDelay(1000)
.retryAttemptedLogLevel(LoggingLevel.WARN));
4.2 路由级别的ErrorHandler
from("direct:start").id("sample-route")
.errorHandler(deadLetterChannel("log:DLC")
.maximumRedeliveries(5).retryAttemptedLogLevel(LoggingLevel.INFO)
.redeliveryDelay(250).backOffMultiplier(2))
.log("User ${} is calling us")
.filter(simple("${} == 'Kaboom'"))
.throwException(new AuthorizationException("Forbidden"))
.end()
.to("mock:done");