重新启动由多个线程运行的Spring批处理作业

时间:2015-10-30 00:50:29

标签: spring-batch restart throttling

我们有一个要求,我们从文件中读取文件,并将其写入平面文件。我的问题是FlatFileItemReader会跟踪它处理的记录,这样如果作业在中间失败,它可以在失败的地方找到它。

例如,让我们说节流限制为2,commit-interval为10,我的文件有20条记录。让我们说thread1正在处理前10条记录和 thread2正在处理接下来的10条记录。如果thread2的所有10条记录都成功处理,而thread1由于一条错误记录而失败,因此整个作业失败。下次 当作业重新启动时,弹簧如何识别未处理的记录?

使用多个线程处理文件的更好方法是什么,同时在中间失败时能够重新开始。

<batch:job job-repository="jobRepository" id="insertIntoCsvFromCsvJob">
        <batch:step id="step1">
            <batch:tasklet transaction-manager="transactionManager"
                task-executor="taskExecutor" throttle-limit="${throttle-limit}">
                <batch:chunk reader="csvFileItemReader" writer="customWriter" processor="compositeProcessor
                    commit-interval="${commit-interval}" >
                </batch:chunk>
            </batch:tasklet>
        </batch:step>
    </batch:job>

    <bean id="csvFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">
         <property name="resource" value="classpath:files/input.csv" />         
        <property name="lineMapper" ref="fieldSetMapper" />
    </bean>

    <bean id="csvFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
        <property name="resource" value="file:c:/outout.csv" />
        <property name="shouldDeleteIfExists" value="true" />
        <property name="lineAggregator" ref="lineAggregator" />
    </bean>

    <bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor" />

1 个答案:

答案 0 :(得分:0)

不,它不会。

我甚至会说你的代码迟早会破裂。问题是FlatFileItemReader(分别是FlatFileItemWriter)的read(分别是write方法)不是线程安全的。

如果要异步使用它们,则需要实现包装器ItemWriter和ItemReader,以同步对FlatFileItemReader / Writer的调用。

但是,当然,如果只使用FlatFileItemReader / Writer的标准实现,那么整个中间的重新启动将无法工作,因为无法保证块的顺序。问题是一个块可能超过另一个块,导致执行上下文中的读取位置指针在被超越的块之后移动。但是,如果被超越的块失败,则执行上下文中的位置将指示已成功处理失败块的条目。

当然,您还可以在适配器中实现逻辑,在该适配器中,您可以跟踪已处理的条目,并且只有在您知道所有先前的条目已经处理并且已被写入时才向前移动位置指针。