我有一个Spring Boot Batch应用程序:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LoadApplication {
public static void main(String[] args) {
SpringApplication.run(LoadApplication.class, args);
}
}
在@Configuration
类中也注明了@EnableBatchProcessing
,我定义了以下批处理作业bean:
@Bean
public Job loadJob(JobBuilderFactory jobs, Step stepLoadFile, Step stepArchiveFile) {
return jobs.get("loadJob")
.incrementer(new RunIdIncrementer())
.start(stepLoadFile)
.next(stepArchiveFile)
.build();
}
批处理作业stepLoadFile
读取一个平面文件(见下文)并将文件数据写入数据库。 stepArchiveFile
然后将文件移动到另一个目录。
通常,工作需要在指定时间每天(周二至周六)运行一次。但是,如果找不到平面文件,则作业失败并需要每30分钟重新运行一次,直到成功或达到最大数量(例如5)的尝试。重新运行成功后,作业不应再次运行,直到下一个正常运行时间。此外,理想情况下,系统应防止同一作业的并发运行。如何才能做到这一切?
注意:重新运行不需要选择上一个作业运行失败的位置。这是因为块大小设置为大于文件中的项目数。
我在@Configuration
课程中尝试了这一点(注意:我还在配置和主类中添加了@EnableRetry
):
@Bean
public ItemReader<Test> reader(LineMapper<Test> lineMapper, ApplicationProperties properties) {
FlatFileItemReader<Test> flatFileItemReader = new FlatFileItemReader<Test>() {
@Override
@Retryable(value = {ItemStreamException.class}, maxAttempts=5)
public void open(ExecutionContext executionContext) throws ItemStreamException {
super.open(executionContext);
}
@Override
@Retryable(maxAttempts=5)
public Holding read() throws UnexpectedInputException, ParseException, Exception {
return super.read();
}
};
flatFileItemReader.setResource(new FileSystemResource(properties.getLoadFile()));
flatFileItemReader.setLineMapper(lineMapper);
return flatFileItemReader;
}
抛出 ItemStreamException
并退出应用程序而不重试。
答案 0 :(得分:6)
您可以通过在LoadApplication类
中添加以下组件来安排@Component
@EnableScheduling
class ScheduledTasks {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job job;
/**The pattern is a list of six single space-separated fields:
* representing second, minute, hour, day, month, weekday.
* Month and weekday names can be given as the first three letters of the English names.
* Example patterns:
"0 0 * * * *" = the top of every hour of every day.*
"*\/10 * * * * *" = every ten seconds. Remove 2nd character, it is escape
"0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.
"0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.
"0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays
"0 0 0 25 12 ?" = every Christmas Day at midnight
*/
@Scheduled(cron = "0 0/30 * * * TUE-SAT")
public void runJob() throws Exception {
jobLauncher.run(job, new JobParameters());
}
}
要重试失败的步骤,您可能需要在作业步骤中对其进行配置
<chunk reader="itemReader" writer="itemWriter"
commit-interval="2" retry-limit="5">
<retryable-exception-classes>
<include class="java.io.FileNotFoundException"/>
</retryable-exception-classes>
</chunk>
此外,如果您将弹簧批次元数据表存储在光盘而不是内存存储中,则弹出批处理不会再次运行相同的作业。
答案 1 :(得分:0)
在步骤声明中使用条件流程。
<step id="readWrite">
<tasklet>(...)</tasklet>
<next on="FAILED" to="scheduleNext" />
</step>
<step id="scheduleNext">
<tasklet ref="schedulerTasklet">
</step>
<bean id="schedulerTasklet" class="SchedulerTasklet"/>
并在SchedulerTasklet中安排下一次运行:
public class SchedulerTasklet implements Tasklet {
@Autowired private TaskScheduler taskScheduler;
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
Runnable task = new Runnable() {
public void run() {
run your job here
}
};
taskScheduler.schedule(task, delay);
return RepeatStatus.FINISHED;
}
}