Spring Batch FlowJobBuilder:并行和顺序执行“jobStep”类型的步骤

时间:2016-05-12 16:09:10

标签: java multithreading spring-batch job-scheduling

我的工作由不同的jobSteps组成。 我想一起触发一批这些JobSteps(JobStep1 | JobStep2 | JobStep3)(在不同的线程中使用AsyncTaskExecutor运行) 完成其他JobSteps时的最后一个JobStep(JobStep 4)。 所以我为每个JobStep创建了不同的Flow,并使用AsyncTaskExecutor将它们放在一个Flow中。 我还为最后一个JobStep制作了一个Flow。

JobStep1 | JobStep2 |完成后的JobStep3 JobStep 4

以下代码代表我的实施:

 Flow flowJob1= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep1).end(); 

 Flow flowJob2= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep2).end(); 

Flow flowJob3= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep3).end(); 

Flow flowJob4= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep4).end(); 

 Flow splitFlow = new FlowBuilder<Flow>("splitflow").split(new SimpleAsyncTaskExecutor()).add(flowJob1,flowJob2,flowJob3).build(); 

然后在创作中我使用这个功能:

JobFlowBuilder jobFlowBuilder = jobBuilderFactory.get(jobName).repository(jobRepository)
                .start((Flow)splitFlow);

            jobFlowBuilder.next(flowJob4);
        FlowJobBuilder flowJobBuilder= jobFlowBuilder.build();
        Job parentJob = flowJobBuilder.build();
        return parentJob;

问题是: 主Job不会等待所有JobSteps(在不同的线程中)完成,然后运行下一个JObStep。我是否应该采取任何弹簧批量配置来解决这个问题?

2 个答案:

答案 0 :(得分:1)

您希望将JobStep 1-3合并为一个FlowStep。然后,您可以使用常规SimpleJobBuilder来建立自己的工作。

Flow flowJob1= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep1).end(); 

Flow flowJob2= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep2).end(); 

Flow flowJob3= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep3).end(); 

// Don't need this
// Flow flowJob4= new FlowBuilder<Flow>(jobStep.getName()).from((JobStep)jobStep4).end(); 

Flow splitFlow = new FlowBuilder<Flow>("splitflow").split(new SimpleAsyncTaskExecutor()).add(flowJob1,flowJob2,flowJob3).build();

FlowStep flowStep = new FlowStep(splitFlow);

SimpleJobBuilder jobBuilder = new JobBuilder(yourJobName).start(flowStep);

jobBuilder.next(jobStep4);

答案 1 :(得分:1)

您能否提供有关如何创建jobStep的更多信息?

TL; DR:

@Bean
public Step jobStepJobStep1(JobLauncher jobLauncher) {
        return this.stepBuilderFactory.get("jobStepJobStep1")
                                .job(job())
                                .launcher(jobLauncher)
                                .parametersExtractor(jobParametersExtractor())
                                .build();
}

尝试从jobStep定义中删除启动器。它为我工作。 我猜这可能是this帖子中的问题。

背景

我的工作流程是:
1.并行运行Job1,Job2,Job3。我通过split()提供执行程序。而所有这些工作实际上都是JobSteps
2.不管1)的结果如何,执行EndJob

    @Bean
    public Job dataSync(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
        Step pricingJobStep = new JobStepBuilder(new StepBuilder("pricingJobStep"))
                .job(pricingJob())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(transactionManager)
                .build();
        Flow pricingFlow = new FlowBuilder<Flow>("pricing-flow").start(
                pricingJobStep
        ).build();

        Step referenceJobStep = new JobStepBuilder(new StepBuilder("referenceJobStep"))
                .job(referenceJob())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(transactionManager)
                .build();

        Flow referenceFlow = new FlowBuilder<Flow>("reference-flow").start(
                referenceJobStep
        ).build();
        Step tradeJobStep = new JobStepBuilder(new StepBuilder("tradeJobStep"))
                .job(tradeJob())
                .launcher(jobLauncher)
                .repository(jobRepository)
                .transactionManager(transactionManager)
                .build();
        Flow tradeFlow = new FlowBuilder<Flow>("trade-flow").start(
                tradeJobStep
        ).build();
        SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor("ETL-EXEC");


        Flow etlFlow = new FlowBuilder<Flow>("etl-flow")
                .split(simpleAsyncTaskExecutor)
                .add(pricingFlow,referenceFlow,tradeFlow)
                .build();


        return jobBuilderFactory.get("data-sync")
                .start(etlFlow)
                .on("COMPLETED")
                .to(finalStep())
                .from(etlFlow)
                .on("FAILED")
                .to(finalStep())
                .end().build();
    }

我正在通过@Scheduled运行此作业 当我运行每个jobStep中注入的启动器时,它们都将作为单独的作业被调用。我分配给split()的执行器仅在步骤级别执行。

在下面的日志中,ETL-EXEC2是我分配给拆分的执行程序。 在拆分中,每个流程实际上是另一项工作。因此,它们由分配给Job启动器的执行器执行。即cTaskExecutor-2

2019-10-24 00:34:06.218  INFO 28776 --- [      ETL-EXEC2] o.s.batch.core.job.SimpleStepHandler     : Executing step: [referenceJobStep]
2019-10-24 00:34:06.359  INFO 28776 --- [cTaskExecutor-2] o.s.b.c.l.support.SimpleJobLauncher      : Job: [SimpleJob: [name=reference-job]] launched with the following parameters: [{name=0}]
2019-10-24 00:34:06.449  INFO 28776 --- [cTaskExecutor-2] o.s.batch.core.job.SimpleStepHandler     : Executing step: [reference-etl]

我的猜测是,这可能就是为什么我无法拥有可以等待所有jobSteps的最终任务的原因。仅仅是因为它们是在不同的执行器中启动的,并且对流程没有任何控制。