【问题标题】:Java batch: jobContext transientUserData not passed through stepsJava批处理:jobContext transientUserData未通过步骤
【发布时间】:2023-03-06 19:47:02
【问题描述】:

我正在使用 jsr-352 规范的 JBeret 实现。

这是我的工作配置,简而言之:

<job id="expired-customer-cancellation" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd"
     version="1.0" jsl-name="job-parent" parent="job-parent">
    <step id="step1" next="step2">
        <chunk item-count="#{jobParameters['chunksize']}?:3">
            <reader ref="eccReader">
            </reader>
            <writer ref="eccWriter" />
        </chunk>
        <partition>
            <mapper ref="eccMapper">
                <properties>
                    <property name="threads" value="#{jobParameters['threads']}?:3"/>
                    <property name="records" value="#{jobParameters['records']}?:30"/>
                </properties>
            </mapper>
        </partition>
    </step>
    <step id="step2">
        <batchlet ref="eccMailBatchlet" />
    </step>
</job>

Itemwriter 类执行如下操作:

@Named
public class EccWriter extends AbstractItemWriter {

    @Inject
    Logger logger;

    @Inject
    JobContext jobContext;

    @Override
    public void writeItems(List<Object> list) throws Exception {
        @SuppressWarnings("unchecked")
        ArrayList<String> processed = Optional.ofNullable(jobContext.getTransientUserData()).map(ArrayList.class::cast).orElse(new ArrayList<String>());
        list.stream().map(UserLogin.class::cast).forEach(input -> {

            if (someConditions) {

                processed.add(input.getUserId());

            }
        });

        jobContext.setTransientUserData(processed); // update job transient data with processed list
    }
}

现在我希望在 step2 上调用 jobContext.getTransientUserData() 时获得更新的列表,而我得到的只是一个 null 值。

此外,每个分区都有自己的jobContext.transientUserData,所以它在分区开始时总是以null值开始。

我认为 jobContext 本身可能会因其名称而误导常见错误。

在整个工作中带来一些数据的自然方式是什么?

【问题讨论】:

    标签: java jsr352 jberet


    【解决方案1】:

    这是当前 API 中的一个空白,“线程本地”行为可能令人惊讶,我同意。

    您可以使用的一种技术是使用步骤持久用户数据。

    例如从第 1 步开始:

    StepExecution.setPersistentUserData(processed);

    然后从第 2 步开始:

    @Inject 
    JobContext ctx;
    
    List<StepExecution> stepExecs = BatchRuntime.getJobOperator().getStepExecutions(ctx.getInstanceId());
    
    // ... not shown here, but sort through stepExecs and find the one from step1.
    StepExecution step2Exec = ... ;  
    
    Serializable userData = step2Exec.getPersistentUserData()
    

    这已被认为是一个需要改进的领域,应该考虑在 Jakarta Batch(规范的新家)的未来增强中。

    【讨论】:

    • 感谢您的提示。另一种可能的方法是通过生产者使用作业范围对象。另见developer.jboss.org/thread/276911
    • 好主意,我的回答至少对任何实现都有好处,对于特定的实现可能有更好的方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-10
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多