看来camel的NotifyBuilder在正常消息处理中可以工作,但在抛出异常时不起作用。
请参阅以下测试用例,其中我创建了以下路线
direct:route-a
将“a”添加到列表中并传递给 direct:route-b
direct:route-b
将“b”添加到列表中并引发异常errorHandler
路由至 direct:dead-letter
作为 deadLetterChannel
direct:dead-letter
将“死亡”添加到列表中当我向
direct:route-a
发送消息时,我可以看到列表包含“a”,“b”,“dead”
但是
NotifyBuilder
和 direct:route-b
的 direct:dead-letter
由于某种原因不匹配。
NotifyBuilder
是否存在抛出异常时它们不匹配的错误?我是否错误地使用了NotifyBuilder
?我已经尝试了 NotifyBuilder.whenDone(1)
和 NotifyBuilder.whenFailed(1)
,但都没有导致匹配。
查看 NotifyBuilder javadoc 我看到以下评论
whenDone(...)
done 和completed 之间的区别在于done 还可以包含失败的消息,而completed 则仅是成功处理的消息。
import lombok.extern.slf4j.Slf4j;
import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.builder.NotifyBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.impl.engine.DefaultProducerTemplate;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
@Slf4j
public class NotifyBuilderTest {
private CamelContext camelContext;
private ProducerTemplate producerTemplate;
private List<String> list;
@BeforeEach
public void beforeEach() throws Exception {
list = new LinkedList<>();
camelContext = new DefaultCamelContext();
camelContext.addRoutes(new RouteBuilder() {
@Override
public void configure() {
from("direct:route-a")
.process(exchange -> list.add("a"))
.to("direct:route-b");
from("direct:route-b")
.process(exchange -> list.add("b"))
.process(exchange -> { throw new Exception("foo"); });
errorHandler(deadLetterChannel("direct:dead-letter"));
from("direct:dead-letter")
.process(exchange -> list.add("dead"));
}
});
producerTemplate = new DefaultProducerTemplate(camelContext);
camelContext.start();
producerTemplate.start();
}
@AfterEach
public void afterEach() {
producerTemplate.stop();
camelContext.stop();
}
@Test
public void testNotify() {
NotifyBuilder notifierA = new NotifyBuilder(camelContext)
.from("direct:route-a")
.whenDone(1)
.create();
NotifyBuilder notifierB = new NotifyBuilder(camelContext)
.from("direct:route-b")
.whenDone(1)
.create();
NotifyBuilder notifierDead = new NotifyBuilder(camelContext)
.from("direct:dead-letter")
.whenDone(1)
.create();
producerTemplate.sendBody("direct:route-a", null);
// this succeeds
assertThat(list).containsExactly("a", "b", "dead");
// this succeeds
assertThat(notifierA.matches(5, TimeUnit.SECONDS)).isTrue();
// this fails
assertThat(notifierB.matches(5, TimeUnit.SECONDS)).isTrue();
// this fails
assertThat(notifierDead.matches(5, TimeUnit.SECONDS)).isTrue();
}
}
事实证明,
NotifyBuilder.from(...)
仅匹配管道的入口点(在我的例子中为direct:route-a
)。我能够通过使用 NotifyBuilder.from(...)
来匹配 route-a
和 NotifyBuilder.wereSentTo(...)
来匹配后续路线来解决我的问题。
我重构了测试用例如下
@Test
public void testNotify() {
NotifyBuilder notifierA = new NotifyBuilder(camelContext)
.from("direct:route-a")
.whenDone(1)
.create();
NotifyBuilder notifierB = new NotifyBuilder(camelContext)
.wereSentTo("direct:route-b")
.whenDone(1)
.create();
NotifyBuilder notifierDead = new NotifyBuilder(camelContext)
.wereSentTo("direct:dead-letter")
.whenDone(1)
.create();
producerTemplate.sendBody("direct:route-a", null);
assertThat(list).containsExactly("a", "b", "dead");
assertThat(notifierA.matches(5, TimeUnit.SECONDS)).isTrue();
assertThat(notifierB.matches(5, TimeUnit.SECONDS)).isTrue();
assertThat(notifierDead.matches(5, TimeUnit.SECONDS)).isTrue();
}