我在Camel中有一个路由,我想在发生异常时重试,但是我想设置一个属性,以便路由可以在第二次尝试稍微不同时尝试在重试时再次发生错误。这是一条路线,说明了我现在正在尝试的想法。
from("direct:onExceptionTest")
.onException(Exception.class)
.maximumRedeliveries(1)
.log("Retrying")
.setProperty("retrying", constant(true))
.end()
.log("Start")
.choice()
.when(property("retrying").isNull())
.log("Throwing")
.throwException(new Exception("Hello world"))
.end()
.end()
.log("Done")
显然这不是真正的路线;整个choice
主体只是在某些情况下模拟我的组件错误。我希望看到以下消息记录:
Start
Throwing
Retrying
Start
Done
但我实际看到的是:
Start
Throwing
Retrying
Failed delivery for (MessageId: ... on ExchangeId: ...). Exhausted after delivery attempt: 2 caught: java.lang.Exception: Hello world. Processed by failure processor: FatalFallbackErrorHandler[Pipeline[[Channel[Log(onExceptionTest)[Retrying]], Channel[setProperty(retrying, true)]]]]
我尝试将handled(true)
添加到异常处理程序中,但所有这一切都会抑制错误消息。我没有看到第二个“开始”或“完成”日志消息。
为什么我的路线不像我期望的那样行事,我需要做些什么来让它按照我想要的方式行事呢?
from("direct:onExceptionTest")
.onException(Exception.class)
.onWhen(property("retrying").isNull()) // don't retry forever
.log("Retrying")
.setProperty("retrying", constant(true))
.handled(true)
.to("direct:onExceptionTest") // is recursion bad?
.end()
.log("Start")
.choice()
.when(property("retrying").isNull())
.log("Throwing")
.throwException(new Exception("Hello world"))
.end()
.end()
.log("Done")
答案 0 :(得分:3)
使用onRedelivery
和Processor
设置属性:
String KEY = "retrying";
from("direct:onExceptionTest")
.onException(RuntimeException.class)
.onRedelivery(new Processor() { // Sets a processor that should be processed before a redelivery attempt.
@Override
public void process(final Exchange exchange) throws Exception {
LOG.info("Retrying");
exchange.setProperty(KEY, true);
}
})
.maximumRedeliveries(1)
.handled(true)
.end()
.log("Start")
.process(new Processor() {
@Override
public void process(final Exchange exchange) throws Exception {
LOG.info("No problem");
}
})
.process(new Processor() {
@Override
public void process(final Exchange exchange) throws Exception {
if (exchange.getProperty(KEY) == null) {
LOG.info("Throwing");
throw new RuntimeException("Hello World");
}
else {
LOG.info("No throwing");
}
}
})
.log("Done");
打印
[ main] route1 INFO Start
[ main] OnExceptionHandler INFO No problem
[ main] OnExceptionHandler INFO Throwing
[ main] OnExceptionHandler INFO Retrying
[ main] OnExceptionHandler INFO No throwing
[ main] route1 INFO Done
正如@ProgrammerDan所指出的那样,只有失败的处理器被重新执行,而不是第一个没有任何问题的处理器。
修改强>
如果必须重新执行所有处理,那么您可以使用doTry
和doCatch
的子路线,如下所示:
from("direct:onExceptionTest")
.doTry()
.to("direct:subroute")
.doCatch(RuntimeException.class)
.setProperty(KEY, constant(true))
.to("direct:subroute")
.end()
.log("Done");
from("direct:subroute")
.log("Start")
.process(new Processor() {
@Override
public void process(final Exchange exchange) throws Exception {
LOG.info("No problem");
}
})
.process(new Processor() {
@Override
public void process(final Exchange exchange) throws Exception {
if (exchange.getProperty(KEY) == null) {
LOG.info("Throwing");
throw new RuntimeException("Hello World");
}
else {
LOG.info("No throwing");
}
}
});
来自Camel Docs:
使用
doTry
..doCatch
..doFinally
时,常规的Camel错误处理程序不适用。这意味着任何onException
或类似的东西都不会触发。原因是doTry
..doCatch
..doFinally
实际上是它自己的错误处理程序,它的目的是模仿和工作,就像try / catch / finally如何在Java中工作一样。 / p>
答案 1 :(得分:2)
关于骆驼的重新传递机制,需要考虑几点。首先,查看the docs on the topic,这可能会挑战您对Camel如何处理重新传递的假设。我已经联系到的一点是,Camel尝试在失败时重新启动,它不会从路径的开头重新开始(正如您所假设的那样)。如果我正确理解文档(我有一段时间没有尝试过这种模式)你基本上是在告诉它多次重试抛出一个异常,我怀疑你想要测试它。
其次,我建议直接在onException()
处理器链中进行备用处理,如演示a little further down in the same docs。基本上,您可以指定通过自定义处理器处理邮件的方式,并使用handled(true)
和stop()
表示无需进一步处理。
总而言之,重新传递通常意味着处理典型的端点传输故障,例如间歇性连接丢失,接收服务器瞬间不可用等等,最有意义的是“再试一次”并对合理的成功期望。如果您需要更复杂的逻辑来处理重试,请在onException()
处理器链中使用自定义处理器或一系列处理器。