配置一个 Step
以支持重启
Step
for Restart
在 “Configuring and Running a Job” 部分,讨论了 Job
的重启。重启对步骤有许多影响,因此可能需要一些特定的配置。
设置启动限制
有许多场景需要你控制 Step
可以启动的次数。例如,你可能需要配置某个特定的 Step
,使其仅运行一次,因为它会破坏某些必须手动修复后才能再次运行的资源。这可以在步骤级别进行配置,因为不同的步骤可能有不同的要求。一个只能执行一次的 Step
可以与一个可以无限运行的 Step
作为同一个 Job
的一部分存在。
- Java
- XML
下面的代码片段展示了 Java 中启动限制配置的一个示例:
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.startLimit(1)
.build();
}
下面的代码片段展示了 XML 中启动限制配置的一个示例:
<step id="step1">
<tasklet start-limit="1">
<chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
</tasklet>
</step>
上一个示例中显示的步骤只能运行一次。 再次尝试运行它将导致抛出 StartLimitExceededException
。 请注意,启动限制的默认值为 Integer.MAX_VALUE
。
重新启动已完成的 Step
在可重启的任务情况下,可能有一个或多个步骤应该始终运行,无论它们第一次是否成功。例如,可能是验证步骤,或者是在处理之前清理资源的 Step
。在重启任务的正常处理过程中,任何状态为 COMPLETED
(意味着它已经成功完成)的步骤都会被跳过。将 allow-start-if-complete
设置为 true
可以覆盖此行为,从而使该步骤始终运行。
- Java
- XML
下面的代码片段展示了如何在 Java 中定义一个可重启的任务:
@Bean
public Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("step1", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(itemReader())
.writer(itemWriter())
.allowStartIfComplete(true)
.build();
}
下面的代码片段展示了如何在 XML 中定义一个可重启的任务:
<step id="step1">
<tasklet allow-start-if-complete="true">
<chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
</tasklet>
</step>
Step
重启配置示例
- Java
- XML
下面的 Java 示例展示了如何配置一个作业,使其具有可重启的步骤:
@Bean
public Job footballJob(JobRepository jobRepository, Step playerLoad, Step gameLoad, Step playerSummarization) {
return new JobBuilder("footballJob", jobRepository)
.start(playerLoad)
.next(gameLoad)
.next(playerSummarization)
.build();
}
@Bean
public Step playerLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("playerLoad", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(playerFileItemReader())
.writer(playerWriter())
.build();
}
@Bean
public Step gameLoad(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("gameLoad", jobRepository)
.allowStartIfComplete(true)
.<String, String>chunk(10, transactionManager)
.reader(gameFileItemReader())
.writer(gameWriter())
.build();
}
@Bean
public Step playerSummarization(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("playerSummarization", jobRepository)
.startLimit(2)
.<String, String>chunk(10, transactionManager)
.reader(playerSummarizationSource())
.writer(summaryWriter())
.build();
}
下面的 XML 示例展示了如何配置一个作业,使其具有可重启的步骤:
<job id="footballJob" restartable="true">
<step id="playerload" next="gameLoad">
<tasklet>
<chunk reader="playerFileItemReader" writer="playerWriter"
commit-interval="10" />
</tasklet>
</step>
<step id="gameLoad" next="playerSummarization">
<tasklet allow-start-if-complete="true">
<chunk reader="gameFileItemReader" writer="gameWriter"
commit-interval="10"/>
</tasklet>
</step>
<step id="playerSummarization">
<tasklet start-limit="2">
<chunk reader="playerSummarizationSource" writer="summaryWriter"
commit-interval="10"/>
</tasklet>
</step>
</job>
前面示例中的配置适用于一个加载足球比赛信息并对其进行总结的任务。该任务包含三个步骤:playerLoad
、gameLoad
和 playerSummarization
。playerLoad
步骤从一个平面文件中加载球员信息,而 gameLoad
步骤则对比赛信息执行相同的操作。最后一步 playerSummarization
根据提供的比赛信息对每个球员的统计数据进行总结。
假设由 playerLoad
加载的文件只需加载一次,而 gameLoad
可以加载特定目录中找到的任何比赛文件,并在成功加载到数据库后将其删除。因此,playerLoad
步骤不包含额外的配置,它可以启动任意次数,如果已完成则会被跳过。然而,gameLoad
步骤需要每次运行,以防自上次运行以来添加了额外的文件。它的 allow-start-if-complete
被设置为 true
,以确保始终启动。(假设加载比赛的数据库表上有一个处理指示器,以确保总结步骤能够正确找到新比赛。)
总结步骤是该任务中最重要的一部分,其启动限制被配置为 2。这是非常有用的,因为如果此步骤持续失败,将向控制任务执行的操作员返回一个新的退出代码,并且在人工干预之前它无法再次启动。
此任务为本文档提供了一个示例,与样本项目中的 footballJob
不同。
本节的其余部分描述了 footballJob
示例中每次运行发生的情况。
运行 1:
-
playerLoad
运行并成功完成,将 400 名玩家添加到PLAYERS
表中。 -
gameLoad
运行并处理了 11 个游戏数据文件,将其内容加载到GAMES
表中。 -
playerSummarization
开始处理,但在 5 分钟后失败。
运行 2:
-
playerLoad
不会运行,因为它已经成功完成,而allow-start-if-complete
为false
(默认值)。 -
gameLoad
再次运行并处理另外 2 个文件,将其内容加载到GAMES
表中(同时使用一个进程指示器表明它们尚未被处理)。 -
playerSummarization
开始处理所有剩余的游戏数据(使用进程指示器进行过滤),并在 30 分钟后再次失败。
运行 3:
-
playerLoad
不会运行,因为它已经成功完成,并且allow-start-if-complete
为false
(默认值)。 -
gameLoad
再次运行并处理另外 2 个文件,将其内容加载到GAMES
表中(同时有一个进程指示器表明它们尚未被处理)。 -
playerSummarization
不会启动,并且作业立即终止,因为这是playerSummarization
的第三次执行,而其限制仅为 2 次。要么需要提高限制,要么需要将Job
作为新的JobInstance
来执行。