spring-batch icon indicating copy to clipboard operation
spring-batch copied to clipboard

Make JobStep stoppable

Open andrianov17 opened this issue 1 year ago • 0 comments

We use JobStep-based implementation to call another job from a job, but unfortunately it doesn't support step.stop() at the moment when parent job stop request arrives via JobOperator.stop().

There are two moments which require adjustments:

  1. SimpleJobOperator
  2. JobStep along with nested job execution tracking

SimpleJobOperator: It needs additional check in its stop() method as in:

@Override
public boolean stop(long executionId) throws NoSuchJobExecutionException, JobExecutionNotRunningException {
...
                                if (tasklet instanceof StoppableTasklet) {
                                    StepSynchronizationManager.register(stepExecution);
                                    ((StoppableTasklet)tasklet).stop(stepExecution);
                                    StepSynchronizationManager.release();
                                **} else if (step instanceof JobStep) {
                                    StepSynchronizationManager.register(stepExecution);
                                    ((JobStep) step).stop(stepExecution, this);
                                    StepSynchronizationManager.release();
                                }**
...

JobStep: Currently, JobStep doesn't track its nested spawned job execution which would need to be stopped as per request above: ((JobStep) step).stop(stepExecution, this).

We achieve this via JobExecutionListener.beforeJob() and save just spawned job execution ID into parent job's step execution context (that's why, we needed stepExecution parameter above - to find nested job execution ID to be stopped by JobOperator).

JobStep stop() method could roughly look like this:
public void step(StepExecution stepExecution, JobOperator jobOperator) {
                // find spawned job execution from stepExecution (e.g., from its execution context)
                ...
                // This is preventive validation, otherwise, stop() will fail if job has been already completed
                // Validation below is taken from Spring Batch JobOperator.stop()
                JobExecution jobExecution = jobOperator.findExecutionById(childJobExecutionId);
                BatchStatus status = jobExecution.getStatus();
                if (!(status == BatchStatus.STARTED || status == BatchStatus.STARTING)) {
                    // Job is not running
                    LOGGER.warn("{} child job execution execution is not running - it cannot be stopped", childJobExecutionId);
                } else {
                    jobOperator.stop(childJobExecutionId);
                }
}

If similar behavior to track nested job execution ID is hard to implement in generic way, at least, the following default method could be introduced in JobStep:

default protected Long getChildExecutionId(StepExecution stepExecution) {
    return null;
}

In such a way JobStep could be inherited and the method defined accordingly.

Thank you in advance!

andrianov17 avatar Nov 24 '24 15:11 andrianov17