2

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

Thomson Mathew
  • 419
  • 1
  • 9
  • 28
  • Why you are stopping a job if it is running? You requirement is not clear. You need to run the job every hour, so I would design a job instance for each hour (ie add an identifying job parameter with the current hour. This way, if a job instance fails, you can restart only that instance. – Mahmoud Ben Hassine Apr 30 '21 at 08:40
  • first of all thank you very much for the comment. Actually this was for testing instance. In real I have around 400 million records to process and currently batch is the only option. We have a window of 8 hours a day. For example I need to start batch every night 10pm and need to stop at 6am in the morning. Basically I need a pause and resume functionality. It should resume with the next record from last stop. I am trying to make this stop and restart working here. Hope I could give enough details. Thanks again – Thomson Mathew Apr 30 '21 at 13:47
  • I still don't understand what exactly do you ask? How to schedule batch job within the window of time, or how to correctly restart interrupted batch job. If first then you should use `@Scheduled` annotation with `cron` parameter instead of `fixedDelay` parameter – Nikolai Shevchenko Apr 30 '21 at 16:26
  • thanks Nikolai I just updated with an explanation. Hope it works ! – Thomson Mathew Apr 30 '21 at 16:53
  • `Basically I need a pause and resume functionality`: [Stop/restart is essentially pause and resume](https://stackoverflow.com/a/18969564/5019386). You need to detect when the job should stop (ie the end of the batch window) and stop it, see example here: https://stackoverflow.com/a/55066860/5019386. After that, you can restart it where it left off in the next batch window. – Mahmoud Ben Hassine May 03 '21 at 09:01
  • Does this answer your question? [Restart step (or job) after timeout occours](https://stackoverflow.com/questions/55049424/restart-step-or-job-after-timeout-occours) – Mahmoud Ben Hassine May 03 '21 at 09:02
  • Thanks Mahmoud I was trying to implement the listener but I am getting an error while adding the listener to the step. It says "he method listener(Object) is ambiguous for the type SimpleStepBuilder<> – Thomson Mathew May 03 '21 at 18:13
  • "You need to detect when the job should stop" - Actually I was trying to stop the job through scheduler. For example (cron = "0 0 22,6 * * *") So based on boolean value it should start and stop at 10pm and 6am respectively. But my issues is why it is not stopping or starting with execution_id ? – Thomson Mathew May 03 '21 at 18:17
  • The code here is to just test. So every 10 second it should stop or restart based on boolean value. – Thomson Mathew May 03 '21 at 18:20

1 Answers1

1

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

  • thanks for the comment really appreciated but my issues is not with scheduler. Issue is restarting or stopping the batch with execution_id – Thomson Mathew Apr 30 '21 at 16:44