首页 > 解决方案 > 基于表达式处理的事务性 Camel 路由标记交换不起作用

问题描述

我的骆驼路线以事务方式从/到 JMS 消费和生产。如果多次处理失败,我们的要求是丢弃有害消息。我知道更好的选择是将消息移动到死信队列,但出于本练习的目的,丢弃它只是很好。

下面是模拟问题的路由定义:

package com.my.comp.playground;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
import org.springframework.stereotype.Component;

@Component
public class MyRouteBuilder extends RouteBuilder {
    @Override
    public void configure() {
        onException(Exception.class)
                .process(new Processor() {
                    private int failureCounter = 0;
                    @Override
                    public void process(Exchange exchange) {
                        exchange.getIn().setHeader("failureCounter", ++failureCounter);
                    }
                })
                .log("failureCounter = ${header.failureCounter}")
                //.handled(true);
                .handled(header("failureCounter").isGreaterThan(3));

        from("jms:test.queue")
                .routeId("test-route")
                .transacted()
                .process(exchange -> {
                    throw new RuntimeException("No good Pal!");
                })
                .to("mock:discard");
    }
}

所以我要做的是保留一个失败的计数器,如果该计数器大于某个数字,则将异常标记为已处理并提交事务。

注意异常处理末尾的两行代码:

 //.handled(true);
 .handled(header("failureCounter").isGreaterThan(3));

当我使用已header("failureCounter").isGreaterThan(3)处理的条件运行路由时,消息会一次又一次地回滚,我可以在日志中看到 failureCounter 正确增加:

...
[mer[test.queue]] test-route                               : failureCounter = 402
[mer[test.queue]] o.a.c.p.e.DefaultErrorHandler            : Failed delivery for (MessageId: ...
...
[mer[test.queue]] test-route                               : failureCounter = 403
...
[mer[test.queue]] test-route                               : failureCounter = 404
...

但是,当我使用已处理的条件运行路由时,true事务会在第一次失败后立即提交,如下所示:

[mer[test.queue]] test-route                               : failureCounter = 1
[mer[test.queue]] o.a.c.s.spi.TransactionErrorHandler      : Transaction commit (0x52b2f795) redelivered(true)

所以我的问题是:我做错了什么还是我对如何使用handled异常的理解不正确?如果是这样,正确的方法是什么?

标签: apache-camel

解决方案


我不知道这是设计使然还是错误。

当我调试您的案例时,我看到谓词 inhandled()是针对 Camel Exchange 进行评估的。

但是,您的failureCounter标头不在 Exchange 中。因此,表达式的header("failureCounter")计算结果为null并且您的谓词始终为false

在一个简短的测试中,我看到存在异常之前设置的标头,但在异常之后设置的标头(即设置在错误处理程序中)在用于评估谓词的 Exchange 上不存在。


推荐阅读