2014-11-21 88 views
0

我有一个弹簧批处理作业,它使用SkipListener将任何错误输出到错误文件。在一个步骤(读取,处理,写入)中可能出现各种类型的错误,并且跳过监听器知道如何处理它们。这工作得很好。SkipListener处理异常事件

但是,我已经注意到错误正在写入到输出无序。这意味着来自处理器的错误在来自阅读器的任何错误之前被写入。

这导致了我很大的问题,因为我需要在它们的读取的相同的顺序写出错误(你会发现,跳跃极限是出奇的高,提交间隔为1,因此这不是一个大块的问题)。出于所有实际的目的,这是一项非常平凡的工作,并且不会做任何会导致我相信这是造成这种情况的实际读者或处理器内的事情。

这整件事让我感到困惑;这很奇怪。我希望有人能指出我如何解决这个问题的正确方向。即使答案是“这就是它的样子,而且你不能改变它。”

这里是作业定义的相关部分:

<job id="devJob" xmlns="http://www.springframework.org/schema/batch"> 
    ... some steps ... 
    <step id="devProcessStep" next="REMOVED_FOR_SO"> 
     <tasklet> 
      <chunk reader="devFileReader" processor="devItemProcessor" writer="devOutputWriter" commit-interval="1" skip-limit="999999"> 
       <streams> 
        <stream ref="devInputReaderStream" /> 
        <stream ref="devErrorOutputWriterStream" /> 
        <stream ref="devOutputWriterStream" /> 
       </streams> 
       <skippable-exception-classes> 
        <include class="org.springframework.batch.item.ItemReaderException"/> 
        ... others, but removed since it doesn't matter for this question ... 
        <exclude class="org.springframework.batch.item.NonTransientResourceException"/> 
       </skippable-exception-classes> 
      </chunk> 
      <listeners> 
       <listener ref="devSkipListener" /> 
      </listeners> 
     </tasklet> 
    </step> 
    ... more steps ... 
</job> 
... 
<bean id="devSkipListener" class="you.have.to.guess.DevSkipListener" scope="job"> 
    <property name="writer" ref="devErrorOutputWriterStream" /> 
    ... other properties that are based on job parameters ... 
</bean> 
... 
<bean id="devErrorOutputWriter" 
    class="org.springframework.batch.item.file.FlatFileItemWriter" scope="job"> 
    ... a bunch of properties based on job parameters etc. 
</bean> 

这里是SkipListener,只有相关部分包括(请注意,我使用Groovy不是Java,因为这是一个Grails应用程序)

package you.have.to.guess 
// bunch of imports (removed for SO) 
class DevSkipListener implements SkipListener { 

    private static def log = LogFactory.getLog(this) 
    ItemWriter writer 
    // some other properties, not important 

    @Override 
    void onSkipInRead(Throwable e) { 
     log.debug("Skip error in read", e) 
     // some stuff here to figure out the lines 
     writer.write(lines) 
    } 

    @Override 
    void onSkipInProcess(Object item, Throwable e) { 
     log.debug("Skip error in process", e) 
     // some stuff here to figure out the lines 
     writer.write(lines) 
    } 

    @Override 
    void onSkipInWrite(Object item, Throwable e) { 
     log.debug("Skip error in write", e) 
     // some stuff here to figure out the lines 
     writer.write(lines) 
    } 
} 

回答

1

简而言之,SkipListener的合同不保证要处理的项目的顺序。只有侦听器上的方法每跳过一次才会被调用。

+0

您是否介意将我指向源代码的方向,我可以看到当前的实现是如何完成的,并决定是否有另一条路线可以确保错误的顺序得到遵守?我很乐意贡献这个补丁。这是一种耻辱,事实并非如此,因为我怀疑我不是唯一需要输入顺序与输入相同的人。 – 2014-11-21 15:40:04

+1

查看用于处理器/写入器相关跳过的读取相关跳转和“FaultTolerantChunkProcessor”的'FaultTolerantChunkProvider'。如果您提交PR,请务必重新运行*全部*单元测试。这些课程的变化非常敏感。 – 2014-11-21 16:09:51

+1

绝对,谢谢。我不知道什么时候有足够的空闲时间才能做到这一点,但我很欣赏快速反应和附加信息。我想回馈这样一个惊人的项目,我希望这个贡献具有相同的质量。再次感谢迈克尔和你的辛勤工作! – 2014-11-21 16:12:07