【问题标题】:Using end in single step batch job in Spring Batch在 Spring Batch 中的单步批处理作业中使用 end
【发布时间】:2017-11-07 13:39:27
【问题描述】:

我们已经配置了单步批处理作业。一般结构是这样的,

<batch:job id="mainJob">
    <batch:step id="step1">
        <batch:tasklet>
            <batch:chunk reader="fileReader" writer="jmsItemWriter" >
                <batch:retryable-exception-classes>
                    <batch:include class="org.springframework.dao.CannotAcquireLockException"/>
                </batch:retryable-exception-classes>
            </batch:chunk>
        </batch:tasklet>
        <batch:end on="UNKNOWN"/>
        <batch:next on="*" to="step1"/>
        <batch:listeners>
            <batch:listener ref="listener1"/>
            <batch:listener ref="listener2"/>
        </batch:listeners>

    </batch:step>
   <batch:listeners>
        <batch:listener ref="jobListener"/>
   </batch:listeners>
  </batch:job>

fileReader 是 Fl​​atFileItemReader,它逐行读取文件并将每一行传递给“listener2”。在 listener2 中,如果行中有错误,则应将状态设置为“未知”(未失败,因为不应再次启动作业),然后停止作业。

为了做到这一点,我们有。

<batch:end on="UNKNOWN"/>
<batch:next on="*" to="step1"/>

但是批处理作业并没有在 Unknown 上结束,而是因为“next”而进入循环。如果没有提到“下一个”,则有一个例外。

我们如何解决这个问题?

编辑:

对 Dean 的回答的更多解释。

Listener2 逐行获取 FieldSet 即文件条目。在处理这些条目时,如果满足某些条件(也涉及数据库查询),则作业不应读取进一步的文件并停止。由于处理是在不抛出任何异常的覆盖方法“mapFieldSet”中完成的,因此不能使用新异常并且返回 null 只是读取下一行。通常文件有数千行,但在前 2 行中确定是否需要进一步阅读。

【问题讨论】:

  • 根据您的更新,我在下面的答案中添加了更多内容

标签: java spring-batch


【解决方案1】:

你所做的很不标准。这就是我要做的......

  • 删除监听器 2(这不是真正应该如何处理错误)
  • ItemProcessor 中执行验证工作,而不是等待 JMS 编写器失败
  • 对于无效项,要么抛出异常,要么从处理器返回 null
  • 创建一个异常监听器 (StepExecutionListener) 来检查失败异常并翻转 ExitStatus

示例步骤执行监听器afterStep 方法:

public ExitStatus afterStep(StepExecution stepExecution) {
    for (Throwable t : stepExecution.getFailureExceptions()) {
        if ("EXPECTED MESSAGE".equals(t.getMessage())) {
            return ExitStatus.UNKNOWN;
        }
     }
    return null;
}

更新基于有问题的新信息:

根据您的指示,Decider 似乎实际上可能是您最干净的解决方案。

修改工作流程:

<batch:job id="mainJob">
    <batch:decision id="decision" decider="someDecider">
        <next on="PROCESS" to="step1" />
        <end on="STOP" />
        <fail on="*" />
    </batch:decision>
    <batch:step id="step1">
        <!-- . . . -->
    </batch:step>
    <!-- . . . -->
</batch:job>

示例Decider 类:

public class ProcessFileDecider implements JobExecutionDecider {

    private Resource resource;

    @Override
    public FlowExecutionStatus decide(final JobExecution jobExecution, final StepExecution stepExecution) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
            final String lineOne = reader.readLine();
            final String lineTwo = (lineOne != null) ? reader.readLine() : null;

            final boolean processFile = true; //some logic here
            if (processFile) {
                return new FlowExecutionStatus("PROCESS");
            }
            return new FlowExecutionStatus("STOP");

        } catch (final IOException e) {
            throw new IllegalStateException("Hit error deciding whether to process the resource!", e);
        }
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

}

【讨论】:

  • 为您的建议更新了问题。
  • 感谢您的建议。这看起来确实是最干净的解决方案。我会在这里尝试并更新。
  • 效果很好,并且使用自定义退出状态,我也可以记录正确的消息。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-21
  • 2018-05-22
  • 1970-01-01
相关资源
最近更新 更多