Spring boot batch - cannot stop the job. Scheduler called only twice

Viewed 510

I am trying to stop and restart a spring batch job in every 10 seconds. I am trying to do this with job_execution_id but it throws an error saying "No job configuration with the name [loadUserJob] was registered".

This is a test application for a real process where I want to start and stop on specific time of the day. Here is the scheduler method.

@Scheduled(cron = "*/10 * * * * *")
public void batchScheduler() {
    LOG.info("---Beginning of batchScheduler()---");
            
    if(isRunning) {
        try {
            LOG.info("....stopping the job!");              
            
            LOG.info("-----------> 2");             
            jobExecutionId = jobRepository.getLastJobExecution("dataFilterJob", jobParameter).getId();
            LOG.info("##### ExecutionID-1: " + jobExecutionId);
            
            this.isRunning = false;
            this.jobOperator.stop(jobExecutionId);
            
        } catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) {
            
            this.isRunning = true;
            LOG.info("Error in Stopping job!!");
            e.printStackTrace();
        }
    }
    else {
        try {
            LOG.info("Restarting the job....");
            
            LOG.info("-----------> 3"); 
            LOG.info("##### ExecutionID-2: " + jobExecutionId);
            
            this.isRunning = true;
            this.jobOperator.restart(jobExecutionId);
            
        } catch (JobInstanceAlreadyCompleteException | NoSuchJobExecutionException | NoSuchJobException
                | JobRestartException | JobParametersInvalidException e) {
            
            this.isRunning = false;
            LOG.info("Error in Restarting the job!!");
            e.printStackTrace();
        }
    }
    
    LOG.info("---End of batchScheduler()---");
}

jobRepository and jobOperator are autowired in the same class. Not sure why it can't find the job with stopped execution id.

Here is the whole class. I am using CommandLineRunner

@SpringBootApplication
@EnableScheduling
public class DatafilterBatchApplication implements CommandLineRunner{
    public static final Logger LOG = LogManager.getLogger(DatafilterBatchApplication.class);
    
    @Autowired
    private JobLauncher jobLauncher;
    
    @Autowired
    private ApplicationContext context;
    
    @Autowired
    private JobRepository jobRepository;
    
    @Autowired
    private JobOperator jobOperator;
    
    @Autowired
    private JobExplorer jobExplorer;
    
    @Autowired
    private JobRegistry jobRegistry;
    
    long jobExecutionId;
    
    boolean isRunning = false;
    boolean isNotRunning = false;
    private String batchName;
    private String filePath;
    private long currentMillis = System.currentTimeMillis();
    private JobParameters jobParameter;
    
    
    public static void main(String[] args) {
        SpringApplication.run(DatafilterBatchApplication.class, args);
    }


    @Override
    public void run(String... args) throws Exception {
        LOG.info("---Beginning of run()---");       
        
        try {
            if(args.length == 2) {
                batchName = args[0];
                filePath = args[1];
                
                jobParameter = new JobParametersBuilder()
                        .addLong("time", currentMillis)
                        .addString("inputFile", filePath)
                        .toJobParameters();
                
                ExitStatus exitStatus = jobController(jobParameter);
                LOG.info("Job completed with status-" + exitStatus);
            }else {
                LOG.info("Invalid Job Parameters!!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        LOG.info("---End of run()---");
    }
    
    
    public ExitStatus jobController(JobParameters jobParameters) {
        LOG.info("---Beginning of jobController()---");
        
        Job job = this.context.getBean("dataFilterJob", Job.class);
        ExitStatus exitStatus = ExitStatus.UNKNOWN; 
        
        try {
            isRunning = true;                       
            exitStatus = jobLauncher.run(job, jobParameters).getExitStatus();           
            
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
                | JobParametersInvalidException e) {
            
            LOG.info("Error in launching job!!");
            e.printStackTrace();
        }
        
        LOG.info("---End of jobController()---");
        return exitStatus;
    }
    

    @Scheduled(cron = "*/10 * * * * *")
    public void batchScheduler() {
        LOG.info("---Beginning of batchScheduler()---");
                
        if(isRunning) {
            try {
                LOG.info("....stopping the job!");              
                
                LOG.info("-----------> 2");             
                jobExecutionId = jobRepository.getLastJobExecution("dataFilterJob", jobParameter).getId();
                LOG.info("##### ExecutionID-1: " + jobExecutionId);
                
                this.isRunning = false;
                this.jobOperator.stop(jobExecutionId);
                
            } catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) {
                
                this.isRunning = true;
                LOG.info("Error in Stopping job!!");
                e.printStackTrace();
            }
        }
        else {
            try {
                LOG.info("Restarting the job....");
                
                LOG.info("-----------> 3"); 
                LOG.info("##### ExecutionID-2: " + jobExecutionId);
                
                this.isRunning = true;
                this.jobOperator.restart(jobExecutionId);
                
            } catch (JobInstanceAlreadyCompleteException | NoSuchJobExecutionException | NoSuchJobException
                    | JobRestartException | JobParametersInvalidException e) {
                
                this.isRunning = false;
                LOG.info("Error in Restarting the job!!");
                e.printStackTrace();
            }
        }
        
        LOG.info("---End of batchScheduler()---");
    }


}

Here is the exception screenshot: enter image description here

UPDATE

I tried JobRegistryBeanPostProcessor to set JobRegistry and it seems working

@Autowired
private JobRegistry jobRegistry;

@Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
    JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
    postProcessor.setJobRegistry(jobRegistry);
    return postProcessor;
}

But now it turned out that the scheduler is called only twice and after the second call it is never been called so the batch never ends. Is that a Scheduler issue or JobRegistryBeanPostProcessor is causing this ? because if I remove it then the Scheduler is called frequently at every 10 seconds but throwing same error: "org.springframework.batch.core.launch.NoSuchJobException: No job configuration with the name [dataFilterJob] was registered."

Here is the whole updated class:

@SpringBootApplication
@EnableScheduling
public class DatafilterBatchApplication implements CommandLineRunner{
    public static final Logger LOG = LogManager.getLogger(DatafilterBatchApplication.class);
    
    
    @Autowired
    private JobLauncher jobLauncher;
    
    @Autowired
    private ApplicationContext context;
    
    @Autowired
    private JobRepository jobRepository;
 
    @Autowired
    private JobRegistry jobRegistry;
    
    @Autowired
    private JobOperator jobOperator;
 
    @Autowired
    private JobExplorer jobExplorer;
    
    private String jobName;
    private JobParameters jobParameters;
    private String completionStatus;
    boolean isRunning = false;
    private String filePath;
    

    @Bean
    public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
        JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
        postProcessor.setJobRegistry(jobRegistry);
        return postProcessor;
    }
    
    public static void main(String[] args) {
        SpringApplication.run(DatafilterBatchApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        LOG.info("---Beginning of run()---");       

        try {
            if(args.length == 2) {
                jobName = args[0];
                filePath = args[1];             
                
                ExitStatus exitStatus = jobController(jobName, filePath);
                LOG.info("Job completed with status-" + exitStatus);
            }else {
                LOG.info("Invalid Job Parameters!!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        LOG.info("---End of run()---");
    }
    
    
    public ExitStatus jobController(String jobName, String fileName) {
        LOG.info("---Beginning of jobController()---");
        
        Job job = this.context.getBean(jobName, Job.class);
        ExitStatus exitStatus = ExitStatus.UNKNOWN; 
        
        jobParameters = new JobParametersBuilder()
                .addLong("time", System.currentTimeMillis())
                .addString("inputFile", fileName)
                .toJobParameters();
        
        try {
            isRunning = true;                       
            exitStatus = jobLauncher.run(job, jobParameters).getExitStatus();
            
            if(exitStatus.getExitCode().equals(ApplicationConstants.JOB_EXITSTATUS_STOPPED)) {              
                isRunning = false;
            }
            
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
                | JobParametersInvalidException e) {
            
            LOG.info("Error in launching job!!");
            isRunning = false;
            e.printStackTrace();
        }
        
        LOG.info("---End of jobController()---");
        return exitStatus;
    }
    

    @Scheduled(cron = "*/10 * * * * *")
    public void batchScheduler() {
        LOG.info("---Beginning of batchScheduler()---");
            
        if(isRunning) {
            try {
                LOG.info("....stopping the job!");
                                
                this.isRunning = false;
                jobOperator.stop(jobRepository.getLastJobExecution(jobName, this.jobParameters).getId());
                
            } catch (NoSuchJobExecutionException | JobExecutionNotRunningException e) {
                
                this.isRunning = true;
                LOG.info("Error in Stopping job!!");
                e.printStackTrace();
            }
        }else {
            try {
                LOG.info("Restarting the job....");
                                
                this.isRunning = true;
                jobOperator.restart(jobRepository.getLastJobExecution(jobName, this.jobParameters).getId());
                
            } catch (JobInstanceAlreadyCompleteException | NoSuchJobExecutionException | NoSuchJobException
                    | JobRestartException | JobParametersInvalidException e) {
                
                this.isRunning = false;
                LOG.info("Error in Restarting the job!!");
                e.printStackTrace();
            }
        }       
        
        LOG.info("---End of batchScheduler()---");
    }

}

UPDATE

I think the issue was with JobOperator and as I updated before JobRegistryBeanPostProcessor would be the solution. But as I mentioned my scheduler is called only twice. So once the application starts, it calls after 10 seconds and stop the running job. It again call one more time after 10 seconds and restart the job and that's all. The scheduler never gets called. So the job just continue to run. I have cron for mat as - (cron = "*/10 * * * * *") so it should be calling in every 10 seconds. Can anyone help me to find out what is going on here. Is that something to do with my scheduler ?

UPDATE

I think I should take back

1 Answers

Add the @Scheduled annotation to any method that you wish to run automatically and include @EnableScheduling in a configuration file. and if you want to schedule it in a chosen time add @Scheduled(cron = "0 45 15 * * ?") to the method like here I schedule my method to run every day at 15h45 for more information you can find here:https://dzone.com/articles/running-on-time-with-springs-scheduled-tasks

Related