如何在Camel中实现超时重试?

4
我应该如何实现Camel路由以达到以下目的?
1. 通过将请求放入JMS代理来调用外部服务 2. 等待它的响应,在另一个线程上,因此原始线程不会被阻塞。 3. 如果请求超时,则重新从步骤2开始(这部分可以通过轮询完成); 否则继续 4. 处理响应 我的测试路由实现
// Simulate receiving message from upstream
from("direct:jmsStart")
        .setExchangePattern(ExchangePattern.InOnly)
        .validate(new TestValidator("Some basic validation"))
        .to("seda:sell");

// Sell Flow Starts
from("seda:sell")
        .transform(new TestTransformer("Convert to internal data structure"))
        .validate(new TestValidator("ValidateSellStatus"))
        .process(new TestProcessor("Prepare request to external system"))
        .process(new TestProcessor("Persist the request to DB")) // <== Any better persistence suggestion??
        .to("seda:jmsRequestToExternal");

// Simulate External System Processing
from("seda:jmsRequestToExternal")
        .log(LoggingLevel.INFO, LOGGER, "External System Processing...")
        .delay(1000).to("seda:jmsReplyFromExternal");

// External System response received
from("seda:jmsReplyFromExternal")
        .process(new TestProcessor("Mark Complete"))
        .log(LoggingLevel.INFO, LOGGER, "Send reply to upstream");

// Trigger retry - resend those requests without a response
from("timer://poller?period=30000")
        .process(new TestProcessor("Get pending requests from DB"))  // <== Any better persistence suggestion??
        .to("seda:jmsRequestToExternal");

为了实现低延迟,所有路由/子路由都不应互相阻塞。请问是否有更好的实现方式可以达到同样的效果?我了解到,Camel上的重新传递机制似乎依赖于阻塞超时或异常机制,这可能不适合低延迟应用程序。

你是指从第一步开始吗?否则你就会一直等待。 - matt helliwell
如果正在读取JMS队列并使用队列消息调用Web服务,则应该能够根据此文档中所述配置队列以进行重试。https://docs.oracle.com/cd/E24152_01/Platform.10-1/ATGPlatformProgGuide/html/s1209configuringfailedmessageredelive01.html - Namphibian
1个回答

18

在Camel中,您需要使用具有重投递策略的异常处理程序,也称为RedeliveryErrorHandler。此错误处理程序将允许您设置重试次数,并设置例如重试之间的延迟等内容。

以下属性适用于RedeliveryErrorHandler

  • MaximumRedeliveries:允许的最大重试次数。 0用于禁用重试,-1将无限尝试重试,直到成功。

  • RedeliveryDelay:每次重试之间的固定延迟(以毫秒为单位)。

  • MaximumRedeliveryDelay:重传延迟的上限(以毫秒为单位)。 当您指定非固定延迟(如指数回退)时使用此功能,以避免延迟增长过大。使用重传的错误处理程序

  • AsyncDelayedRedelivery:指示Camel是否应使用异步延迟重试。当要在未来重新传递重新传递时,Camel通常必须阻止当前线程,直到重新传递的时间。通过启用此选项,您可以让Camel使用计划程序,以便异步线程将执行重新传递。这可确保没有线程被阻塞,而等待再次传递。

  • BackOffMultiplier:指数回退乘数,用于乘以每个连续延迟。RedeliveryDelay是起始延迟。默认情况下禁用指数回退。

  • CollisionAvoidanceFactor:在计算随机延迟偏移量时使用的百分比(以避免在下一次尝试时使用相同的延迟)。将RedeliveryDelay作为起始延迟。默认情况下禁用碰撞回避。

  • DelayPattern:用于计算延迟的模式。该模式允许您为间隔组指定固定的延迟时间。例如,模式“0:1000;5:5000;10:30000”将在第0到4次尝试中使用1秒的延迟,在第5到9次尝试中使用5秒,并在随后的尝试中使用30秒。

  • RetryAttemptedLogLevel:执行重试尝试时使用的日志级别。

  • RetriesExhaustedLogLevel:所有重传尝试失败时使用的日志级别。

  • LogStackTrace布尔值true指定是否在所有重试尝试失败时记录堆栈跟踪。

  • LogRetryStackTrace:指定是否在传递失败时记录堆栈跟踪。

  • LogRetryAttempted:指定是否记录重试尝试。

  • LogExhausted:指定是否记录重试尝试已用尽(当所有重试尝试失败时)。

  • LogHandled:指定是否记录已处理的异常。

在Java中使用它很简单,您可以使用以下代码:

errorHandler(defaultErrorHandler()
.maximumRedeliveries(3) 
.backOffMultiplier(4)
.retryAttemptedLogLevel(LoggingLevel.WARN));

或者如果您想使用Spring XML DSL:

<errorHandler id="myErrorHandler" type="DefaultErrorHandler"
    <redeliveryPolicy maximumRedeliveries="5"
       retryAttemptedLogLevel="WARN"
       backOffMultiplier="2"
       useExponentialBackOff="true"/>
</errorHandler>
你可以使用此功能在一定次数内重试web服务调用,如果无法连接(例如,尝试5次后仍无法连接),则引发异常。

如果超时不会抛出异常,因为使用JMS异步调用外部服务(即非阻塞),该怎么办? - Lewis Wong
你能在问题中提供更多细节吗?似乎有很多我不知道的事情。 - Namphibian
请注意,MaximumRedeliveryDelay 实际上是每次重试之间的延迟时间,而 RedeliveryDelay 是第一次重试前的初始延迟时间。Javadoc 是正确的,但变量名称有些令人困惑。 - WesternGun
这个问题已经8年了,所以可能有些变化。 - Namphibian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接