Camel exception/error 处理事务路由而不导致客户端异常
Camel exception/error handling transacted route without causing client exception
我正在使用一个命令事件驱动的系统,使用 JMS 和 Apache Camel 进行路由。在以下情况下:
我向系统发送请求-回复指令"X".
系统通过交易骆驼路线接收"X"。
在处理 "X" 时,系统发出几个事件,"Y" & "Z",
但作为交易路线的一部分,这些不应被刷新
直到交易完成。
发生运行时异常 - 这应该会导致事务
回滚。
我希望能够拦截异常并用真正的消息(而不是异常)回复客户端。因此,我开始实施错误处理程序:
onException(RuntimeException.class)
.handled(true)
.markRollbackOnly()
.filter(header(Header.REPLY_TO.getName()).isNotNull())
.to(DESTINATION_FOR_EXCEPTION_HANDLING)
.to(DESTINATION_FOR_REPLIES);
其中:
- DESTINATION_FOR_EXCEPTION_HANDLING 是一个接受异常的 bean,returns 是一个消息对象
- DESTINATION_FOR_REPLIES 是一个将 out 主体设置为消息对象的 bean
我遇到的问题是,如果我包含 "markRollbackOnly()" 它:
- 防止 "Y" 和 "Z" 被冲洗 - 好
- 在发出 requestReply 的客户端上导致交换异常 - BAD
如果我不包括它,那么:
- "Y" & "Z" 脸红了 - 不好
- 我在客户端收到了真正的消息对象 - 好
我如何配置 camel 以防止在事务中刷新消息,同时又能够将异常转换为已处理的错误消息?
如果发送到这两个目的地的 onException 使用与 from 相同的 Camel 组件,那么您将需要为此使用一个单独的组件,以便它们是独立的。因为回滚否则会导致它们全部回滚。
假设您使用 ActiveMQ,您只需声明两个组件
<bean id="activemq" ...>
<bean id="activemq2" ...>
然后在onException中使用activemq2。然后可以配置为使用相同的 brokerUrl 等等。对于第二次,您可能需要将其设置为 transacted=false.
我尝试了 Claus 方法,但由于某种原因无法正常工作,我一定是误解了或设置不正确。
最终我通过在内部传播第二个事务解决了这个问题,一个错误处理程序然后我可以 "markRollbackOnlyLast" 第二个事务,但在主事务上用 "good" 消息响应:
TransactionTemplate newTransactionTemplate = new TransactionTemplate(platformTransactionManager);
newTransactionTemplate.setPropagationBehavior(PROPAGATION_REQUIRES_NEW);
Policy requireNewTransaction = new SpringTransactionPolicy(newTransactionTemplate);
onException(RuntimeException.class)
.onWhen(header(Header.REPLY_TO.getName()).isNotNull())
.log(LoggingLevel.ERROR, EXCEPTION_STACKTRACE)
.to(PROCESSOR_FOR_EXCEPTION_HANDLING)
.to(PROCESSOR_FOR_REPLY)
.handled(true)
.markRollbackOnlyLast();
from(FROM)
.policy(requireNewTransaction)...
我正在使用一个命令事件驱动的系统,使用 JMS 和 Apache Camel 进行路由。在以下情况下:
我向系统发送请求-回复指令"X".
系统通过交易骆驼路线接收"X"。
在处理 "X" 时,系统发出几个事件,"Y" & "Z", 但作为交易路线的一部分,这些不应被刷新 直到交易完成。
发生运行时异常 - 这应该会导致事务 回滚。
我希望能够拦截异常并用真正的消息(而不是异常)回复客户端。因此,我开始实施错误处理程序:
onException(RuntimeException.class)
.handled(true)
.markRollbackOnly()
.filter(header(Header.REPLY_TO.getName()).isNotNull())
.to(DESTINATION_FOR_EXCEPTION_HANDLING)
.to(DESTINATION_FOR_REPLIES);
其中:
- DESTINATION_FOR_EXCEPTION_HANDLING 是一个接受异常的 bean,returns 是一个消息对象
- DESTINATION_FOR_REPLIES 是一个将 out 主体设置为消息对象的 bean
我遇到的问题是,如果我包含 "markRollbackOnly()" 它:
- 防止 "Y" 和 "Z" 被冲洗 - 好
- 在发出 requestReply 的客户端上导致交换异常 - BAD
如果我不包括它,那么:
- "Y" & "Z" 脸红了 - 不好
- 我在客户端收到了真正的消息对象 - 好
我如何配置 camel 以防止在事务中刷新消息,同时又能够将异常转换为已处理的错误消息?
如果发送到这两个目的地的 onException 使用与 from 相同的 Camel 组件,那么您将需要为此使用一个单独的组件,以便它们是独立的。因为回滚否则会导致它们全部回滚。
假设您使用 ActiveMQ,您只需声明两个组件
<bean id="activemq" ...>
<bean id="activemq2" ...>
然后在onException中使用activemq2。然后可以配置为使用相同的 brokerUrl 等等。对于第二次,您可能需要将其设置为 transacted=false.
我尝试了 Claus 方法,但由于某种原因无法正常工作,我一定是误解了或设置不正确。
最终我通过在内部传播第二个事务解决了这个问题,一个错误处理程序然后我可以 "markRollbackOnlyLast" 第二个事务,但在主事务上用 "good" 消息响应:
TransactionTemplate newTransactionTemplate = new TransactionTemplate(platformTransactionManager);
newTransactionTemplate.setPropagationBehavior(PROPAGATION_REQUIRES_NEW);
Policy requireNewTransaction = new SpringTransactionPolicy(newTransactionTemplate);
onException(RuntimeException.class)
.onWhen(header(Header.REPLY_TO.getName()).isNotNull())
.log(LoggingLevel.ERROR, EXCEPTION_STACKTRACE)
.to(PROCESSOR_FOR_EXCEPTION_HANDLING)
.to(PROCESSOR_FOR_REPLY)
.handled(true)
.markRollbackOnlyLast();
from(FROM)
.policy(requireNewTransaction)...