【问题标题】:Camel retry control with multiple exceptions带多个异常的骆驼重试控制
【发布时间】:2012-11-21 00:12:40
【问题描述】:

前言:我对 Camel 还很陌生,在尽可能地消化了 Camel 的实际应用之后,我正在将其调整到我正在进行的项目中。在这个项目中,我们有一些相当复杂的错误处理,我想确保我可以在我们对代码进行骆驼化时复制它。

在我们的项目中(与大多数情况一样),有一组我们想要重试的异常和一组我们不想重试的异常 - 但更具体地说,有一组我们比其他项目更想重试(并非所有可恢复的错误可以同样处理)。在这种情况下,我试图定义一个onException 块来更改重新投递策略。但是,似乎 Exchange 维护计数 (Exchange.REDELIVERY_COUNTER),并且此计数不依赖于引发的异常。有没有办法让这个计数特定于给定的异常?

例如 - 我有两个例外 FooExceptionBarException。在我的路线中(或实际上在整个上下文中),我想重试 FooExceptions 10 次,但 BarExceptions 应该只重试 2 次。所以上下文将包含:

<onException>
     <exception>my.exception.FooException</exception>
     <redeliveryPolicy maximumRedeliveries="10" redeliveryDelay="2000"
</onException>

<onException>
      <exception>my.exception.BarException</exception>
      <redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="5000"
</onException>

现在,问题是 - 如果我的应用程序抛出一个 FooException 并重试 4 次(每次抛出一个 FooException),然后在第 5 次尝试时,它抛出一个 BarException,这似乎是这样的工作方式是 Exchange 的 REDELIVERY_COUNTER 为 5,当我将策略重置为仅尝试两次时,它(逻辑上)得出结论认为不应重试路由并将异常抛出。但是,在我的应用程序中,BarExceptions 应该重试两次,无论有多少 FooExceptions 被抛出。同样,如果它交替抛出 Foo 和 Bar 异常,我希望它只增加给定异常的计数器。

Camel in Action 的最后宣传使用retryWhile - 这是获取我正在寻找的那种控制的唯一方法吗?我是否需要创建一个知道每个异常计数的有状态 bean?还是我忽略了一些简单的事情?我想确保当我接近这个重构时,我不会让我们走上一条丑陋的道路。

使用骆驼 2.10.1

【问题讨论】:

    标签: exception-handling apache-camel


    【解决方案1】:

    尝试替换您定义异常的顺序,例如:

    <onException>
          <exception>my.exception.BarException</exception>
          <redeliveryPolicy maximumRedeliveries="2" redeliveryDelay="5000"
    </onException>
    
    <onException>
         <exception>my.exception.FooException</exception>
         <redeliveryPolicy maximumRedeliveries="10" redeliveryDelay="2000"
    </onException>
    

    【讨论】:

    • 如果您使用萨满的测试用例,重新排序似乎不会改变输出。如果有机会,我会尝试在 Spring 配置中进行测试。
    【解决方案2】:

    我通过以下测试检查了您的情况:

    import org.apache.camel.EndpointInject;
    import org.apache.camel.Exchange;
    import org.apache.camel.Produce;
    import org.apache.camel.ProducerTemplate;
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.component.mock.MockEndpoint;
    import org.apache.camel.test.junit4.CamelTestSupport;
    import org.junit.Test;
    
    import java.util.concurrent.atomic.AtomicLong;
    
    /**
     * @author Illarion Kovalchuk
     *         Date: 12/7/12
     *         Time: 2:58 PM
     */
    public class Test extends CamelTestSupport
    {
    
        private static final String MIDDLE_QUEUE = "seda:middle";
    
        @EndpointInject(uri = "mock:result")
        protected MockEndpoint resultEndpoint;
    
        @Produce(uri = "direct:start")
        protected ProducerTemplate template;
    
        private Processor processor = new Processor();
    
        @Test
        public void shouldRedeliverOnErrors() throws Exception
        {
            resultEndpoint.expectedBodiesReceived("Body");
            template.sendBodyAndHeader(MIDDLE_QUEUE, "Body", "Header", "HV");
            resultEndpoint.assertIsNotSatisfied();
        }
    
        @Override
        protected RouteBuilder createRouteBuilder()
        {
            return new RouteBuilder()
            {
                @Override
                public void configure() throws Exception
                {
    
                    onException(FooException.class)
                            .redeliveryDelay(2000)
                            .maximumRedeliveries(10);
    
                    onException(BarException.class)
                            .redeliveryDelay(5000)
                            .maximumRedeliveries(2);
    
                    from(MIDDLE_QUEUE)
                            .bean(Processor.class, "process")
                            .to(resultEndpoint)
                            .end();
                }
            };
        }
    
        public static class Processor
        {
            private static AtomicLong retryState = new AtomicLong(0L);
    
            public static void process(Exchange e) throws FooException, BarException
            {
                long rs = retryState.getAndAdd(1L);
                if (rs < 4)
                {
                    System.err.println("Foo Attempt "+ rs);
                    throw new FooException();
                }
                if (rs == 4)
                {
                    System.err.println("Bar Attempt "+ rs);
                    throw new BarException();
                }
                System.err.println("Normal Attempt "+ rs);
            }
        }
    
        public static class FooException extends Throwable
        {
        }
    
        private static class BarException extends Throwable
        {
        }
    }
    

    因此,您的同意被批准:在 BarException 之后交付尝试已用尽,即使我们只有 4 个 FooExceptions 和 1 个 BarException。

    很遗憾,我现在不能完全回答你的问题,但我正在深入研究它,如果有新的东西会更新我的答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-27
      • 2012-09-09
      • 2018-08-15
      • 2015-06-29
      相关资源
      最近更新 更多