Spring Cloud Data Flow中Spring Batch状态不匹配及重启问题咨询
问题1:让SCDF控制台正确反映Spring Batch作业真实状态
解决spring.cloud.task.batch.fail-on-job-failure=true报错问题
出现"Job must not be null nor empty"错误,是因为远程分区架构中,主任务(master)通过分区管理器调度worker任务,而非直接由TaskJobLauncherApplicationRunner启动Batch作业。该配置仅适用于单任务直接启动Batch作业的场景,无需在master节点配置,应在worker任务的application.properties中添加以下配置:
spring.cloud.task.batch.fail-on-job-failure=true spring.cloud.task.batch.exit-code-on-job-failure=1
这样worker任务会在对应分区作业失败时以非0退出码结束,SCDF就能识别到该worker任务执行失败。
关联SCDF任务状态与Batch作业状态
远程分区的master任务本身不会因某个worker失败直接退出,需让master任务感知worker失败状态并将自身Task状态设为失败。可在master的Batch作业中添加监听器,检测到分区step失败时手动抛出异常:
@Bean public JobExecutionListener jobFailureListener() { return new JobExecutionListenerSupport() { @Override public void afterJob(JobExecution jobExecution) { boolean hasFailedStep = jobExecution.getStepExecutions().stream() .anyMatch(stepExecution -> stepExecution.getStatus() == BatchStatus.FAILED); if (hasFailedStep) { jobExecution.setStatus(BatchStatus.FAILED); throw new JobFailedException("One or more partition steps failed"); } } }; }
将该监听器注册到master的Job中,master任务会在有分区失败时抛出异常,SCDF控制台就会显示任务执行失败,与Batch作业状态保持一致。
问题2:仅重启失败的分区作业
默认SCDF作业重启API会触发整个master作业,进而调度所有分区,要实现仅重启失败分区可按以下方式操作:
记录失败分区参数
作业执行时,确保每个分区的参数(如分区ID、数据范围)被记录到batch_step_execution_context中。分区失败后,从数据库batch_step_execution表中找到失败step的STEP_EXECUTION_ID,提取对应分区参数。
自定义重启逻辑,指定单个分区执行
- 修改worker任务的启动参数,支持接收指定分区ID的参数(如
partition.id)。 - 通过SCDF REST API直接触发worker任务,传递失败分区的参数:
curl 'http://localhost:9393/tasks/executions' -i -X POST \ -H 'Content-Type: application/json' \ -d '{ "taskDefinitionName": "your-worker-task", "arguments": [ "--partition.id=2", "--job.parameters=jobId=1" ] }'
- 或在master作业中自定义
Partitioner,重启时根据作业执行上下文筛选失败分区,仅生成对应分区的执行请求。
利用Spring Batch的Step重启能力
通过自定义端点调用Spring Batch原生Step重启接口,单独重启失败的分区step:
@RestController @RequestMapping("/restart") public class PartitionRestartController { @Autowired private JobOperator jobOperator; @PostMapping("/step/{stepExecutionId}") public String restartFailedStep(@PathVariable Long stepExecutionId) throws Exception { return jobOperator.restartStep(stepExecutionId); } }
调用该接口时传入失败分区step的ID,即可单独重启该分区作业,不会触发所有分区。
内容的提问来源于stack exchange,提问作者Sanjay

