我有一个 spring 批处理作业,预计将根据FIFO顺序处理'N'作业ID . 这个 Spring 季批处理作业有5个步骤 .
我们使用DECIDER来确定是否存在任何job-id . 如果是,请转到第一步并运行该job-id的所有步骤 .
我在spring-batch发出的日志中看到"duplicate step"消息,除非第一个作业中的步骤(比如job-id = 1)获得UNKNOWN状态,否则看起来很好 . 在这种情况下,第二个作业(job-id = 2)的相同步骤无法开始说明"Step is in UNKNOWN state, it is dangerous to restart...." . 有没有更好的方法来定义弹出批处理作业来处理'N' job-id .
有一张表保存工作信息 . 每个作业将订单放入订单表 . 可能需要在同一天处理两个作业 . 作业可以插入/更新具有相同修订版(具有其他细节差异)的相同订单编号或相同订单编号的不同修订版 . 批处理程序必须根据作业表中的success_time在FIFO模型中处理这些作业 .
假设表结构如下
Job_Id job_name success_time
1 job1 2014-09-29 10:00:00
2 job2 2014-09-29 13:00:00
Order_id order_number order_revision order_details job_id
1 ABC 1 Test1 1
2 XYZ 1 Test2 1
3 ABC 2 Test1-Rev2 2
示例配置如下所示 . 为简洁起见,我删除了元数据定义并重用了读者和作者 .
<batch:step id="abstractParentStep" abstract="true">
<batch:tasklet>
<batch:chunk commit-interval="100" />
</batch:tasklet>
</batch:step>
<-- Using same reader and writer to simplify scenario depiction -->
<batch:job id="OrderProcessingJob">
<batch:step id="Collect-Statistics-From-Staging-Tables" next="Validate-Order-Mandatory-Fields" parent="abstractParentStep">
<batch:tasklet>
<batch:chunk reader="orderReader" writer="orderWriter" />
</batch:tasklet>
</batch:step>
<batch:step id="Validate-Order-Mandatory-Fields" next="Validate-Item-Mandatory-Fields" parent="abstractParentStep">
<batch:tasklet>
<batch:chunk reader="orderReader" writer="orderWriter" />
</batch:tasklet>
</batch:step>
<batch:step id="Validate-Item-Mandatory-Fields" next="decision" parent="abstractParentStep">
<batch:tasklet>
<batch:chunk reader="orderReader" writer="orderWriter" />
</batch:tasklet>
</batch:step>
<batch:decision id="decision" decider="processMoreJobsDecider">
<batch:next on="REPEAT" to="Validate-Order-Mandatory-Fields" />
<batch:end on="COMPLETED" />
</batch:decision>
</batch:job>
在第一步中,我们将检查需要处理多少个作业(计数)并将其放入ExecutionContext . 在决策程序中,我们检查处理的作业总数是否与计数匹配,如果有更多的job_id要处理,则返回REPEAT状态 .
当第一个作业的步骤保持在UNKNOWN状态和第二个作业(因为决策者确定还有一个job_id要处理)时,如上所述,我们遇到异常,如上所示得到异常消息 .
2 回答
你的问题是你用'下一个'而不是一个开始你的流程 .
我使用Java配置而不是XML,但得到了类似的异常(不是特别有用的错误输出):
修复是第一个 - >开始
大概同样适用于Spring Batch xml配置 .
您应该为每个步骤指定一个唯一的名称 . 如果您使用分区,则会自动为您完成此操作 .
请参阅this gist,文件
partitionedSimple.groovy
(您只需下载文件并运行groovy <filename.groovy>
即可运行所有示例) . 在step1
中,我们确定随后需要的步骤数(硬编码为3)并将其保存在作业上下文中(首先在步骤上下文中然后我们提升) . 我们创建一个分区步骤partitionedStep
,它将启动3个步骤 . 他们的名字是repeatedStep:<partition name>
. 在分区中,我们还在上下文中放置了一个名为partitionIndex
的键,因此我们可以在实现重复步骤的tasklet中检索它 .然后我们运行一个例子,当它处理第2项时我们强制它失败 . 我们得到这些步骤执行:
如果我们然后重新启动此作业并删除错误触发,则只处理第二个项目:
我还添加了一个slightly more complicated example,其中重复步骤实际上是一个流程步骤,步骤名称是手动动态生成的 - 如果你想重复一个流程,这很重要,因为你必须为里面的步骤赋予唯一的名称每次执行流程 .
这也可以在没有分区的情况下完成,使用looping decider . 这里的想法是你有一个重复的包装步骤(
allowStartIfComplete
)并用你想要的步骤包装流程 . 由于步骤范围的bean工厂,这些步骤是按需创建的 . 看似冗余的包装步骤的原因是job()
bean工厂内的流构建器需要提前知道步骤名称以构建转换状态,所以我们"hide"在那一点上的未知步骤在另一步骤中命名 . 也许有办法简化它 . 第一轮的执行是:(通知
repeated-3
永远不会执行)并在第二次运行: