在未经检查的异常情况下,Spring批处理继续作业流程

时间:2017-04-14 21:54:26

标签: spring spring-batch unchecked-exception

我在Spring Batch Tasklet发送电子邮件。

SMTP服务器已关闭,因此未检查MailSendException异常。

过渡的下一步被声明为(来自电子邮件发送):

FlowBuilder<Flow> flowBuilder = new FlowBuilder<Flow>("myFlow")
        .from(sendNotificationStep()).next(nextStep());
即使出现未经检查的异常,也会执行

nextStep()

Spring Batch Framework的常规行为是忽略未经检查的异常吗?

问题是这个异常被静默忽略并且没有记录(我将root记录器设置为WARN)。

why does transaction roll back on RuntimeException but not SQLException

中报告的相反行为

UPDATE 在使用调试器踩到后,我结束了内部:

public class SimpleFlow implements Flow, InitializingBean {

    public FlowExecution resume(String stateName, FlowExecutor executor) throws FlowExecutionException {

         state = nextState(stateName, status, stepExecution);

statusFAILEDstatesendNotificationStepnextState()返回nextStep

catch中有resume

catch (Exception e) {
    executor.close(new FlowExecution(stateName, status));
    throw new FlowExecutionException(String.format("Ended flow=%s at state=%s with exception", name,
                                                  stateName), e);
}

但以前通过以下方式处理异常:

public abstract class AbstractStep implements Step, InitializingBean, BeanNameAware {
    public final void execute(StepExecution stepExecution) throws JobInterruptedException,

    catch (Throwable e) {
        stepExecution.upgradeStatus(determineBatchStatus(e));
        exitStatus = exitStatus.and(getDefaultExitStatusForFailure(e));
        stepExecution.addFailureException(e);
        if (stepExecution.getStatus() == BatchStatus.STOPPED) {
            logger.info(String.format("Encountered interruption executing step %s in job %s : %s", name, stepExecution.getJobExecution().getJobInstance().getJobName(), e.getMessage()));
            if (logger.isDebugEnabled()) {
                logger.debug("Full exception", e);
            }
        }
        else {
            logger.error(String.format("Encountered an error executing step %s in job %s", name, stepExecution.getJobExecution().getJobInstance().getJobName()), e);
        }
    }

批处理管理将问题步骤列为ABANDONED

更新3 重现行为的全功能示例(感谢 Sabir Khan 提供刺伤!):

@SpringBootApplication
@Configuration
@EnableBatchProcessing
public class X {

    private static final Logger logger = LoggerFactory.getLogger(X.class);

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    protected Tasklet tasklet1() {
        return (StepContribution contribution, ChunkContext context) -> {
            logger.warn("Inside tasklet1");
            throw new IllegalStateException("xxx");
            //return RepeatStatus.FINISHED;
        };
    }

    @Bean
    protected Tasklet tasklet2() {
        return (StepContribution contribution, ChunkContext context) -> {
            logger.warn("Inside tasklet2");
            return RepeatStatus.FINISHED;
        };
    }

    @Bean
    public Job job() throws Exception {
        Flow flow = new FlowBuilder<Flow>("myFlow").from(firstStep()).on("*").to(nextStep()).end();
        return this.jobs.get("job").start(flow).end().build();
    }

    @Bean
    protected Step firstStep() {
        return this.steps.get("firstStep").tasklet(tasklet1()).build();
    }

    @Bean
    protected Step nextStep() {
        return this.steps.get("nextStep").tasklet(tasklet2()).build();
    }

    public static void main(String[] args) throws Exception {
        System.exit(SpringApplication.exit(SpringApplication.run(X.class, args)));
    }
}

1 个答案:

答案 0 :(得分:1)

不,这不是正常的Spring Batch行为,我从未见过您所描述的内容。

我认为,Spring Batch并没有在被检查或未检查的异常抛出中做出区分 - 在顺序执行的情况下抛出异常时,流将停止。

显然,如果正在执行并行步骤或执行,其他部分的执行将继续。

在某个地方,可能已经在您的代码中处理了异常(静默使用),这就是执行可能继续下一步的原因。

我已经看到我的工作中抛出了两类异常,并且工作行为与我编码 skip-retry 和其他异常处理机制的方式相同,而且它与Spring Batch无关 - 这是纯粹的Java的。

我不确定我是否误读了您的问题,但下面的示例代码并没有按照您描述的方式运行。 Step-1抛出未经检查的异常并且执行在那里停止,因为我无论如何都没有处理它。

@SpringBootApplication(exclude = { DataSource.class,
        DataSourceAutoConfiguration.class })
@Configuration
@EnableBatchProcessing
public class AppConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(AppConfiguration.class);

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Autowired
    private JavaMailSender javaMailSender;

    @Bean
    protected Tasklet tasklet() {

        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution,
                    ChunkContext context) {


                MimeMessage message = javaMailSender.createMimeMessage();
                javaMailSender.send(message);

                return RepeatStatus.FINISHED;

            }
        };

    }

    @Bean
    protected Tasklet tasklet2() {

        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution,
                    ChunkContext context) {

                return RepeatStatus.FINISHED;
            }
        };

    }

    @Bean
    public Job job() throws Exception {

        Flow flow = new FlowBuilder<Flow>("myFlow").from(step1()).next(nextStep()).end();
        return this.jobs.get("job").start(flow).end().build();

    }

    @Bean
    protected Step step1() {
        return this.steps.get("step1").tasklet(tasklet()).build();
    }

    @Bean
    protected Step nextStep() {
        return this.steps.get("nextStep").tasklet(tasklet2()).build();
    }

    public static void main(String[] args) throws Exception {
        System.exit(SpringApplication.exit(SpringApplication.run(AppConfiguration.class, args)));
    }

}

希望它有所帮助!!

相关问题