如何将错误从执行程序通道路由到错误通道?

时间:2018-09-26 21:16:48

标签: java error-handling spring-integration executor

请参阅附图进行设置。以下说明。

enter image description here

有一个公共输入通道可以接收请求。从这个输入通道,有两个流:

  1. 流1-将请求存储到DB

  2. 流程2-将业务处理/转发请求发送到其他外部系统

我希望流程1和流程2彼此独立。因此,我将流程1放在执行程序通道上。这样,流程1中的错误不会中断流程2。

流程1的说明:

  1. 代码从公共输入通道读取请求并将其放入执行者通道。
  2. DBStore类从执行者通道读取请求并将其存储到DB中。
  3. 我还有一个错误通道(对项目中的所有类通用),它将悄悄地记录错误

我所拥有的:

在绿色框中的代码中,我定义了ExpressionEvaluatingRequestHandlerAdvice,以便将执行程序通道上的任何错误发送到错误通道。我假设ExpressionEvaluatingRequestHandlerAdvice将自动应用于执行者通道。

相反,如果出现错误,它将被重新发布到“公共输入通道”并重复处理,直到队列填满。

我需要什么

我希望将执行程序通道上的任何错误发送到错误通道,在该通道中将对其进行静默记录并处理消息。

从公用输入通道读取并在执行器通道上读取的代码:

    @Configuration
@EnableIntegration
public class InputChanneltoExecutorChannelConfig {

//DEFINING THE EXECUTOR CHANNEL
    @Bean
    public TaskExecutor taskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }

    @Bean(name="executorChannelToDB")
    public ExecutorChannel outboundRequests() {
        return new ExecutorChannel(taskExecutor());
    }
//DEFINE FAILURE CHANNEL FOR USE IN ExpressionEvaluatingRequestHandlerAdvice
    @Bean(name = "DBFailureChannel")
    public static MessageChannel getFailureChannel() {
        return new DirectChannel();
    }   

//MAIN METHOD THAT READS FROM INPUT CHANNEL AND SENDS TO EXECUTOR CHANNEL
    @Bean
    public IntegrationFlow outboundtoDB() {
        return IntegrationFlows
                .from("commonInputChannel")
                /*
                 * We publish the msg to be stored into the DB onto a executor
                 * channel (so that the DB operation is processed on a separate
                 * thread).
                 */
                .channel("executorChannelToDB").get();
                /****************************************************************************
                        *********************************************************
                 * How do I route the error from executor channel to error channel over here?
                        **********************************************************
                 ****************************************************************************/
    }

    /*
     * Create an advice bean to handle DB errors. In case of failure, send
     * response to a separate channel.
     */
    @Bean
    public ExpressionEvaluatingRequestHandlerAdvice expressionAdvice() {
        ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
        advice.setFailureChannelName("DBFailureChannel");
        advice.setOnFailureExpressionString("'##Error while storing request into DB'");
        advice.setTrapException(true);
        return advice;
    }

    /*
     * We create a separate flow for DB failure because in future we may need
     * other actions such as retries/notify support in addition to logging.
     */
    @Bean
    public IntegrationFlow failure() {
        return IntegrationFlows.from("DBFailureChannel")
                .channel("errorChannel").get();

    }   
}

更新: 按照加里的建议,更新了ERROR_CHANNEL和REPLY_CHANNEL。

   @Bean
    public IntegrationFlow outboundtoDB() {
        return IntegrationFlows
                .from("commonInputChannel")
                //Setting Headers
                .enrichHeaders(h -> h.header(MessageHeaders.ERROR_CHANNEL, "errorChannel", true))
                .enrichHeaders(h -> h.header(MessageHeaders.REPLY_CHANNEL, "DBSuccessChannel", true))
                .channel("executorChannelToDB").get();

DBSuccess通道设置为处理如下响应:

@Bean
public IntegrationFlow success() {
    return IntegrationFlows
            .from("DBSuccessChannel")
            .wireTap(
                    flow -> flow.handle(msg -> logger
                            .info("Response from storing in DB : "
                                    + msg.getPayload()))).get();
}

但是我仍然会收到错误消息,

  

2018-09-26 23:34:47.398错误17186 --- [SimpleAsyncTaskExecutor-465]   o.s.integration.handler.LoggingHandler:   org.springframework.messaging.MessageHandlingException:嵌套   异常是java.time.format.DateTimeParseException:文本'sample   “创建时间戳记”无法在索引0处解析,   failedMessage = GenericMessage   [payload=com.td.sba.iep.schema.InstructionRs@37919153,   标头= {errorChannel = errorChannel,    jms_destination = commonInputChannel ,Solace_JMS_Prop_IS_Reply_Message = false,优先级= 0,   jms_timestamp = 1538018141672,JMS_Solace_isXML = true,   replyChannel = DBSuccessChannel,jms_redelivered = true,   JMS_Solace_DeliverToOne = false,JMS_Solace_ElidingEligible = false,   JMS_Solace_DeadMsgQueueEligible = false,   id = ff6c2ea6-b6d6-c67a-7943-6b7db33bb977,   jms_messageId = ID:49.37.4.163d608166190664e70:0,   timestamp = 1538019287394}]

在这里,仍然将jms_destination设置为输入通道,并且错误不断被重新发布到commonInputChannel。 你能帮忙吗?

1 个答案:

答案 0 :(得分:0)

该建议将无济于事,因为它仅适用于该终结点-不适用于下游流,无论如何,即使这样做,也将成功移交给执行程序,并且所有下游异常均由执行程序处理(并用ErrorHandlingTaskExecutor包装在MessagePublishingErrorHandler中。

尝试用标题增强器替换该组件,然后设置errorChannel标题。或者,您也可以使用配置了错误通道的MPEH自己包装TE(执行程序通道将检测到TE已经是EHTE)。

编辑

这对我来说很好...

@SpringBootApplication
public class So52526134Application {

    public static void main(String[] args) {
        SpringApplication.run(So52526134Application.class, args);
    }

    @Bean
    public IntegrationFlow mainFlow() {
        return IntegrationFlows.from(() -> "foo", e -> e.poller(Pollers.fixedDelay(5000)))
                .enrichHeaders(h -> h.header(MessageHeaders.ERROR_CHANNEL, "myErrors.input"))
                .channel(MessageChannels.executor(executor()))
                .handle((p, h) -> {
                    throw new RuntimeException("foo");
                })
                .get();
    }

    @Bean
    public IntegrationFlow myErrors() {
        return f -> f.handle((p, h) -> {
            System.out.println("in my error flow");
            return p;
        })
        .handle(System.out::println);
    }

    @Bean
    public TaskExecutor executor() {
        return new ThreadPoolTaskExecutor();
    }

}

in my error flow
ErrorMessage [payload=org.springframework.messaging.MessageHandlingException: ...