如何安排Spring Boot Batch应用程序

时间:2016-08-02 17:51:31

标签: spring spring-boot scheduled-tasks spring-batch

我有一个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并退出应用程序而不重试。

2 个答案:

答案 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;
    }
}