Spring批处理步骤不执行

Spring Batch Step does not execute

我正在尝试解决 Spring 批处理中最近困扰我们系统的问题。我们有一份工作,在大多数情况下工作得很好。这是一个下载和处理数据的多步骤作业。

问题是有时作业会爆炸。也许我们尝试连接的服务器抛出错误,或者我们在工作中途关闭了服务器。此时我们的石英调度程序下次尝试 运行 作业时 它似乎什么也没做 。以下是此职位定义的简化版本:

<batch:job id="job.download-stuff" restartable="true">
<batch:validator ref="downloadValidator"/>
<batch:step id="job.download-stuff.download">
    <batch:tasklet ref="salesChannelOrderDownloader" transaction-manager="transactionManager">
        <batch:transaction-attributes isolation="READ_UNCOMMITTED" propagation="NOT_SUPPORTED"/>
        <batch:listeners>
            <batch:listener ref="downloadListener"/>
            <batch:listener ref="loggingContextStepListener" />
        </batch:listeners>
    </batch:tasklet>
    <batch:next on="CONTINUE" to="job.download-stuff.process-stuff.step" />
    <batch:end on="*" />
</batch:step>
<batch:step id="job.download-stuff.process-stuff.step">
    ...
</batch:step>
<batch:listeners>
    <batch:listener ref="loggingContextJobListener"/>
</batch:listeners>

一旦进入此状态,downloadValidator 运行s,但它永远不会进入第一步 download-stuff.download。我在 tasklet 中设置了一个断点,但它永远不会进入。

如果我清除存储在我们的 mysql 数据库中的所有 spring 批处理 table,然后重新启动服务器,它将开始工作再次,但我宁愿了解是什么阻止它在这一点上正常运行,而不是采用焦土战术来获得这份工作 运行ning.

我是Spring批处理的新手,委婉地说,如果我遗漏了重要的细节,请原谅我。我设置了断点并打开了日志记录以了解我能做什么。

到目前为止,我通过数据库观察到的是条目似乎不再写入 BATCH_STEP_EXECUTION 和 BATCH_JOB_EXECUTION tables。

作业没有 BATCH_JOB_EXECUTION 个未处于已完成状态的条目,也没有 BATCH_STEP_EXECUTION 个未处于已完成状态的条目

您会看到定义了一个 batch:validator,我已经确认 spring 批处理调用了该验证器并且它成功通过(设置断点并单步执行)。第一步没有执行。

loggingContextJobListener 和 loggingContextStepListener 似乎都没有触发。可能是什么原因造成的?

更新 我仔细查看了添加为 batch:listener 的 downloadListener。这是afterStep的源代码:

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public ExitStatus afterStep(StepExecution stepExecution) {
    long runSeconds = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - nanoStart);

    // If Success - we're good
    if (stepExecution.getStatus() == BatchStatus.COMPLETED) {
        Long endTs = stepExecution.getExecutionContext().getLong("toTime");
        Date toTime = new Date(endTs);
        handleSuccess(toTime, stepExecution.getWriteCount());
        return null;
    }

    // Otherwise - record errors
    List<Throwable> failures = stepExecution.getFailureExceptions();
    handleError(failures);
    return ExitStatus.FAILED;
}

我确认 return ExitStatus.FAILED 行执行并且抛出的异常记录在 failureExceptions 中。似乎一旦发生这种情况,BATCH_JOB_EXECUTION 条目就处于完成状态(和 exit_code)并且 STEP_EXECUTION 失败。

此时,BATCH_JOB_EXECUTION_PARAMS table 中的条目仍然存在。我实际上尝试修改它们的 KEY_NAME 和值列的值,但这仍然不允许作业 运行。 只要有参数绑定到 JOB_EXECUTION_ID,另一个属于同一个 BATCH_JOB_INSTANCE 的作业就不能 运行。

一旦我删除了 BATCH_JOB_EXECUTION_PARAMS 中针对特定 JOB_EXECUTION_ID 的条目,另一个 BATCH_JOB_EXECUTION 可以 运行,即使所有 BATCH_JOB_EXECUTION 条目都处于完成状态。

所以我想我有两个问题 - 这是正确的行为吗?如果是这样,是什么阻止了 BATCH_JOB_EXECUTION_PARAMS 被删除,我该如何删除它们?

JobParametersValidator,在您的情况下,downloadValidator bean 在作业开始前 运行s。

你的情况是你传递作业的参数与 "blown up" JobInstance 相同。但是,由于该作业以戏剧性的方式失败,因此它可能没有进入失败状态。

您可以 运行 具有不同参数的作业(以获取新的作业实例)或尝试将前 step/job 的状态更新为 BATCH_STEP_EXECUTION 或 BATCH_JOB_EXECUTION 重新启动前。

更新(问题中添加了新信息) 你必须小心你在这里的工作流程。是的,您的步骤失败了,但是您的上下文文件表明作业应该 END(完成)除 CONTINUE.

以外的任何内容
<batch:next on="CONTINUE" to="job.download-stuff.process-stuff.step" />
<batch:end on="*" />

首先,要非常小心结束于 *。在您的场景中,它会导致您以 ExitCodeFAILED 完成工作("success")。另外,成功步骤的默认 ExitCodeCOMPLETED,而不是 CONTINUE,所以要小心。

<!-- nothing to me indicates you'd get CONTINUE here, so I changed it -->
<batch:next on="COMPLETED" to="job.download-stuff.process-stuff.step" />

<!-- if you ever have reason to stop here -->
<batch:end on="END" /> 

<!-- always fail on anything unexpected -->
<batch:fail on="*" />

有同样的问题,在 test/debug 过程中我保持作业名称和参数相同,确保您正在更改作业名称或作业参数以获得不同的 JobExecution