Spring batch продолжает выполнение задания в случае непроверенного исключения
Я отправляю письмо в Spring Batch Tasklet
,
SMTP сервер не работает, поэтому не проверен MailSendException
исключение произошло.
Следующий шаг в переходе объявляется как (от отправки электронной почты):
FlowBuilder<Flow> flowBuilder = new FlowBuilder<Flow>("myFlow")
.from(sendNotificationStep()).next(nextStep());
а также nextStep()
выполняется даже в случае непроверенного исключения.
Это нормальное поведение Spring Batch Framework для игнорирования непроверенных исключений?
Проблема в том, что это исключение игнорируется и не регистрируется (я установил root
войти в WARN
).
Несколько противоположное поведение сообщается в том, почему транзакция откатывается на RuntimeException, но не на SQLException
ОБНОВЛЕНИЕ После шага с отладчиком я заканчиваю внутри:
public class SimpleFlow implements Flow, InitializingBean {
public FlowExecution resume(String stateName, FlowExecutor executor) throws FlowExecutionException {
state = nextState(stateName, status, stepExecution);
status
является FAILED
, state
является sendNotificationStep
а также nextState()
вернуть 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 Полностью функциональный пример для воспроизведения поведения (спасибо Сабиру Хану за предоставление удара!):
@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 ответ
Нет, это не нормальное поведение Spring Batch, и я никогда не видел, что вы описываете.
Я думаю, что Spring Batch не делает различий в том, что исключение выбрано, проверяется или не проверяется - поток остановится в тот самый момент, когда выдается исключение для случая последовательного выполнения.
Очевидно, что выполнение других частей будет продолжаться, если выполняются параллельные шаги или выполнения.
Где-то внизу, исключение могло быть обработано в вашем коде (съедено молча), и поэтому выполнение могло продолжаться до следующего шага.
Я видел, как обе категории исключений создавались в моих работах, и задание ведет себя так, как я кодировал пропуски-повторы и другие механизмы обработки исключений, и это не имеет никакого отношения к Spring Batch - это чистая Java.
Я не уверен, что неправильно понял ваш вопрос, но приведенный ниже пример кода не работает так, как вы описали. Шаг 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)));
}
}
Надеюсь, поможет!!