定义2个拆分以并行运行一组步骤

时间:2016-11-09 23:16:41

标签: spring spring-batch

我有一个作业配置,我在这里加载了一组文件,在加载了一组文件之后我还要并行加载另一组文件,但只有在第一组完全加载后才能加载。第二组具有第一组的参考字段。我认为我可以使用第二个拆分但从未使它工作,在xsd中,你似乎可以定义多个拆分,显然流程对我的要求没有帮助。 那么如何定义两组并行流并按顺序运行?

<job>
  <split>
    <flow>
      <step next="step2"/>
      <step id="step2"/>
    </flow>
    <flow>
      <step ...>
    </flow>
  </split>
 <split ../>

Asoub是对的,它很简单,我做了一个简单的配置,它起作用了。因此,我得到的原始问题似乎有一些其他问题,在定义2个拆分时会导致问题。

我使用的简单配置:

<batch:job id="batchJob" restartable="true">
    <batch:split id="x" next="y">
        <batch:flow>
            <batch:step id="a">
                <batch:tasklet allow-start-if-complete="true">
                    <batch:chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
                </batch:tasklet>
            </batch:step>
        </batch:flow>
        <batch:flow>
            <batch:step id="b">
                <batch:tasklet allow-start-if-complete="true">
                    <batch:chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
                </batch:tasklet>
            </batch:step>
        </batch:flow>
    </batch:split>
    <batch:split id="y" next="e">
        <batch:flow>
            <batch:step id="c">
                <batch:tasklet allow-start-if-complete="true">
                    <batch:chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
                </batch:tasklet>
            </batch:step>
        </batch:flow>
        <batch:flow>
            <batch:step id="d">
                <batch:tasklet allow-start-if-complete="true">
                    <batch:chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
                </batch:tasklet>
            </batch:step>
        </batch:flow>
    </batch:split>
    <batch:step id="e">
        <batch:tasklet allow-start-if-complete="true">
            <batch:chunk reader="itemReader" writer="itemWriter" commit-interval="2"/>
        </batch:tasklet>
    </batch:step>
</batch:job>


INFO: Job: [FlowJob: [name=batchJob]] launched with the following parameters: [{random=994444}]
Nov 23, 2016 11:33:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [a]
Nov 23, 2016 11:33:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [b]
Nov 23, 2016 11:33:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [c]
Nov 23, 2016 11:33:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [d]
Nov 23, 2016 11:33:24 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO: Executing step: [e]
Nov 23, 2016 11:33:25 PM org.springframework.batch.core.launch.support.SimpleJobLauncher run
INFO: Job: [FlowJob: [name=batchJob]] completed with the following parameters: [{random=994444}] and the following status: [COMPLETED]

2 个答案:

答案 0 :(得分:1)

我会使用两个分区步骤。每个分区程序都负责识别其各自集合中的文件,以便处理并发的子步骤

<job>
  <step name="loadFirstSet">
    <partition partitioner="firstSetPartitioner">
      <handler task-executor="asyncTaskExecutor" />
      <step name="loadFileFromSetOne>
        <tasklet>
          <chunk reader="someReader" writer="someWriter" commit-interval="#{jobParameters['commit.interval']}" />
        </tasklet>
      </step>
    </partition>
  </step>
  <step name="loadSecondSet">
    <partition partitioner="secondSetPartitioner">
      <handler task-executor="asyncTaskExecutor" />
      <step name="loadFileFromSecondSet>
        <tasklet>
          <chunk reader="someOtherReader" writer="someOtherWriter" commit-interval="#{jobParameters['another.commit.interval']}" />
        </tasklet>
      </step>
    </partition>
  </step>
</job>

答案 1 :(得分:1)

正如我在评论中所说,&#34;那么如何定义两组顺序流程,这些并行流程按顺序运行到每个?&#34;本身没有意义,你不能平行和顺序地开始两步。

我仍然认为你想在步骤1中开始加载file2,当step1中的file1完成加载时#34;。这意味着加载文件发生在步骤的中间。我看到了解决这个问题的两种方法。

让我们说这是您的配置:

<job id="job1">
    <split id="split1" task-executor="taskExecutor" next="step3">
        <flow>
            <step id="step1" parent="s1"/>
        </flow>
        <flow>
            <step id="step2" parent="s2"/>
        </flow>
    </split>
    <step id="step3" parent="s4"/> <!-- not important here -->
</job>

<beans:bean id="taskExecutor" class="org.spr...SimpleAsyncTaskExecutor"/>

但是这将立即启动你的平行步骤。您需要阻止步骤2的开始。因此,您需要在step2的Delegate中使用reader,它将立即停止加载file2,并等待信号启动读。在step1的代码中,您可以考虑加载完成,然后向step2的委托阅读器发出信号以开始加载file2。

第二个解决方案是:您创建自己的SimpleAsyncTaskExecutor,它将启动step1并等待来自step1的信号开始step2。它基本上是第一个解决方案,但您在自定义Executor而不是Delegate读者中等待信号。 (您可以从SimpleAsyncTaskExecutor复制源代码以获得想法)

这是有代价的,如果step1永远不会到达它开始加载的信号step2的部分,你的批次将永远挂起。也许加载中的异常可能导致这种情况。至于信号机制,Java有很多方法可以做到这一点(wait()notifiy(),锁,信号量,非标准库可能。)

我不认为在春季批次中会有一些平行步骤触发器之王(但如果有,有人发布它)。

在问你的问题时我已经回答了一点,你需要2次拆分:第一次加载文件A,第二次加载文件B。

<job id="job1">
    <split id="splitForSet_A" task-executor="taskExecutor" next="splitForSet_B">
        <flow><step id="step1" parent="s1"/></flow>
        <flow><step id="step2" parent="s2"/></flow>
        <flow><step id="step3" parent="s3"/></flow>
    </split>
   <split id="splitForSet_B" task-executor="taskExecutor" next="stepWhatever">
        <flow><step id="step4" parent="s4"/></flow>
        <flow><step id="step5" parent="s5"/></flow>
        <flow><step id="step6" parent="s6"/></flow>
    </split>
    <step id="stepWhatever" parent="sx"/>
</job>

步骤1,2和3将以并行(并加载文件集A)运行,然后,一旦它们全部结束,第二次拆分(splitForSet_B)将启动并运行步骤4,5和6平行。拆分基本上是包含以并行运行的步骤的步骤。

您只需在每个步骤中指定要使用的文件(因此,对于第二次拆分中的步骤进行第一次拆分时的步骤将有所不同。