назначение разных обработчиков ошибок каждому обработчику в цепочке

У меня есть приложение, определяющее простой поток, в котором цепочка сервисов должна вызываться в определенном порядке для выполнения некоторых функций. Интеграция Spring и ее DSL кажутся подходящими для этого сценария.

Любая из этих отдельных служб может выйти из строя (эти службы являются вызовами внешних приложений), после чего цепочка должна остановиться. Мало того, поток управления также необходимо перенаправить куда-то еще, в зависимости от неисправной службы. Другими словами, мне нужен другой обработчик ошибок для каждой службы.

Проблема в том, что мне трудно найти, как это сделать, и я был бы очень признателен, если бы кто-нибудь мог указать мне правильное направление. Вот как я решал проблему до сих пор:

@Configuration
@EnableAutoConfiguration
@IntegrationComponentScan
public class Application {

public static void main(String[] args) throws InterruptedException {
    ConfigurableApplicationContext ctx =
            SpringApplication.run(Application.class, args);

    System.out.println(ctx.getBean(MySource.class).send("foo"));

    ctx.close();
}

@MessagingGateway
public interface MySource {

    @Gateway(requestChannel = "flow.input")
    String send(String string);

}

@Bean
public IntegrationFlow flow() {
    return f -> f
            .handle(String.class, (i, map) -> {
 //             if (true){
 //                 throw new RuntimeException();
 //             }
                System.out.println(i);
                return i + "a";
            })
            .handle(String.class, (i, map) -> {
                System.out.println(i);
                return i + "b";
            })
            .handle(String.class, (i, map) -> {
                System.out.println(i);
                return i + "c";
            });
   }
}

Я искал, как установить обработчик ошибок/канал для каждого из этих обработчиков, но не нашел ничего полезного.

Я почти сдался в своих поисках и начал писать свой собственный код (вздох), он выглядит примерно так:

public class FlowHarness {

    public static void main(String[] args) {
        Flow flow = FlowBuilder.flow()
            .nextStep(i -> ((Integer)i) + 1, e -> System.out.println("failed at step 1"))
            .nextStep(i -> ((Integer)i) + 1, e -> System.out.println("failed at step 2"))
            .nextStep(i -> ((Integer)i) + 1, e -> System.out.println("failed at step 3"))
            .build();

        flow.execute(new Integer(1));
    }
}

Аргумент левой стороны .nextStep() является обработчиком, тогда как аргумент правой стороны является обработчиком ошибок. Это очень упрощенно, но я надеюсь, что это иллюстрирует суть.

Несмотря на то, что весь реальный поток может быть написан в большом классе, я думаю, что было бы удобнее разбить каждый из подпотоков на отдельные частные методы/классы. Большое спасибо.


person edu    schedule 29.05.2017    source источник


Ответы (2)


.handle() (а также любая другая конечная точка потребителя) может поставляться с ExpressionEvaluatingRequestHandlerAdvice: http://docs.spring.io/spring-integration/docs/4.3.9.RELEASE/reference/html/messaging.-endpoints-chapter.html#expression-advice

@Bean
public IntegrationFlow advised() {
    return f -> f.handle((GenericHandler<String>) (payload, headers) -> {
        if (payload.equals("good")) {
            return null;
        }
        else {
            throw new RuntimeException("some failure");
        }
    }, c -> c.advice(expressionAdvice()));
}

@Bean
public Advice expressionAdvice() {
    ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice();
    advice.setSuccessChannelName("success.input");
    advice.setOnSuccessExpressionString("payload + ' was successful'");
    advice.setFailureChannelName("failure.input");
    advice.setOnFailureExpressionString(
            "payload + ' was bad, with reason: ' + #exception.cause.message");
    advice.setTrapException(true);
    return advice;
}

@Bean
public IntegrationFlow success() {
    return f -> f.handle(System.out::println);
}

@Bean
public IntegrationFlow failure() {
    return f -> f.handle(System.out::println);
}
person Artem Bilan    schedule 29.05.2017

Поскольку вы хотите, чтобы цепочка перестала выполняться при сбое. Я предлагаю вам использовать собственное исключение с соответствующими обработчиками.

person Vaibhav Gupta    schedule 29.05.2017
comment
вопрос был о том, как это сделать... все равно спасибо :) Артем смог привести пример - person edu; 29.05.2017