从Spring Batch Tasklet获取进度信息

时间:2019-10-23 14:34:38

标签: spring-boot spring-batch

我正在尝试为当前正在运行的spring batch tasklet设置和检索进度信息。

例如,我有一个基于步骤的简单春季批处理作业。

   public Step jobStep() {
        return stepBuilderFactory.get(JOB_STEP_1)
                .tasklet((contribution, chunkContext) -> {
...
                }).build();
   }

tasklet是一个执行某些操作的简单循环,可能会花费很多时间。

在循环中的每个迭代之后,我在例如JobExecutionContext中设置一些进度信息。

chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("myJobStatus", "10 of 100 finished");

从另一个线程(例如,休息服务),我想检查实际tasklet的进度,为此我使用JobExplorer

String status = (String)jobExplorer.getJobExecution(jobId).getExecutionContext().get("myJobStatus");

不幸的是,仅在步骤或作业完成时才设置myJobStatus属性。我什至尝试将简单的循环替换为步骤循环,但结果相同。

还有另一种方法来设置和访问当前正在运行的作业的进度信息吗?

我正在将DefaultBatchConfigurer与基于JDBC的JobRepository等一起使用。

2 个答案:

答案 0 :(得分:0)

此步骤听起来像是一个很好的候选者,可以重构为更多的Reader->Writer步骤,而不是Tasklet中的循环。在每X个项目块之后,Spring Batch框架将使用最新的读/写计数来更新步骤执行。

对于长时间运行的步骤,这还具有对每个块进行提交的优点,从而使可重新启动性的负担减轻了,而不是等到Tasklet发出单个较大的提交之前等所有工作都完成。

答案 1 :(得分:0)

您的问题是,您正在将进度信息保存在作业执行上下文中,该信息将在完成步骤后保存在作业存储库中。您需要使用步骤执行上下文,因为它保存在Tasklet的每次提交中。以下是参考文档中Execution context部分的摘录:

  

它们是两个不同的ExecutionContext。作用域为步骤的一个保存在步骤的每个提交点,而作用域为作业的一个保存在每次执行步骤之间。

因此,如果将进度信息存储在步骤执行上下文(而不是作业执行上下文)中,则应该能够使用作业浏览器从其他线程获取进度信息。我假设您的tasklet做了一些工作,将进度保存在步骤执行上下文中,然后返回CONTINUABLE,直到没有更多工作要做并在此时返回FINISHED。我在this repo中有一个完整的示例,但这是相关的部分:

class MyTasklet implements Tasklet {

    private int progress;

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        RepeatStatus repeatStatus;
        if (moreWork()) {
            doSomeWork();
            repeatStatus = RepeatStatus.CONTINUABLE;
        } else {
            repeatStatus = RepeatStatus.FINISHED;
        }
        reportProgress(chunkContext);
        return repeatStatus;
    }

    private void reportProgress(ChunkContext chunkContext) {
        chunkContext.getStepContext().getStepExecution()
                .getExecutionContext().putInt("progress", this.progress++);
    }

    private void doSomeWork() throws Exception {
        Thread.sleep(5000);
        System.out.println("doing some work..");
    }

    private boolean moreWork() {
        return this.progress < 100;
    }
}