6

I am seeing this exception when stopping a running job using jobOperator.stop(id) or when I want to restart it using jobOperator.restart(id). I don't have any idea why the MapJobRegistry is empty ... Am I missing a step ?
I have reproduced the problem using the complete example from https://github.com/spring-guides/gs-batch-processing.git

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

   @Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;
// end::setup[]

@Autowired
JobRepository jobRepository;

// tag::readerwriterprocessor[]
@Bean
public FlatFileItemReader<Person> reader() {
    return new FlatFileItemReaderBuilder<Person>()
        .name("personItemReader")
        .resource(new ClassPathResource("sample-data.csv"))
        .delimited()
        .names(new String[]{"firstName", "lastName"})
        .fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
            setTargetType(Person.class);
        }})
        .build();
}

@Bean
public PersonItemProcessor processor() {
    return new PersonItemProcessor();
}

@Bean
public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder<Person>()
        .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
        .sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
        .dataSource(dataSource)
        .build();
}
// end::readerwriterprocessor[]

// tag::jobstep[]
@Bean
public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
    return jobBuilderFactory.get("importUserJob")
        .incrementer(new RunIdIncrementer())
        .listener(listener)
        .flow(step1)
        .end()
        .build();
}

@Bean
public Step step1(JdbcBatchItemWriter<Person> writer) {
    return stepBuilderFactory.get("step1")
        .<Person, Person> chunk(10)
        .reader(reader())
        .processor(processor())
        .writer(writer)
        .build();
}
// end::jobstep[]

@Bean
public JobLauncher simpleJobLauncher() throws Exception {
    SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
    jobLauncher.setJobRepository(jobRepository);
    jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
    jobLauncher.afterPropertiesSet();
    return jobLauncher;
}
}

The rest controller

@RestController
public class BatchController {

Logger logger = LoggerFactory.getLogger(BatchController.class);

@Autowired
JobLauncher simpleJobLauncher;

@Autowired
Job importUserJob;

@Autowired
JobOperator jobOperator;

@RequestMapping("/startNewJob")
public String handle()  {
    try {
        JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
                .toJobParameters();
        JobExecution jobExecution = simpleJobLauncher.run(importUserJob, jobParameters);

        return jobExecution.toString();
    } catch (Exception e) {
        logger.info(e.getMessage());
        return ("An error has occured, please check the logs");
    }
}

@RequestMapping("/stopJob/{id}")
public Boolean stopJob(@PathVariable Long id) throws Exception {
    logger.info("stopJob "+id);
    return jobOperator.stop(id);
}

@RequestMapping("/restartJob/{id}")
public Long restartJob(@PathVariable Long id) throws Exception {
    logger.info("restartJob "+id);
    return jobOperator.restart(id);
}
}

Stacktrace while restarting the job
2020-11-12 21:47:16.452 ERROR 26252 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.batch.core.launch.NoSuchJobException: No job configuration with the name [importUserJob] was registered] with root cause

org.springframework.batch.core.launch.NoSuchJobException: No job configuration with the name [importUserJob] was registered at org.springframework.batch.core.configuration.support.MapJobRegistry.getJob(MapJobRegistry.java:68) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at com.sun.proxy.$Proxy68.getJob(Unknown Source) ~[na:na] at org.springframework.batch.core.launch.support.SimpleJobOperator.restart(SimpleJobOperator.java:275) ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.batch.core.launch.support.SimpleJobOperator$$FastClassBySpringCGLIB$$44ee6049.invoke() ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:685) ~[spring-aop-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.batch.core.launch.support.SimpleJobOperator$$EnhancerBySpringCGLIB$$853e8727.restart() ~[spring-batch-core-4.2.1.RELEASE.jar:4.2.1.RELEASE] at com.example.batchprocessing.BatchController.restartJob(BatchController.java:60) ~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.2.RELEASE.jar:5.2.2.RELEASE]

0

3 Answers 3

6

I simply added a JobRegistryBeanPostProcessor and set it the jobRegistry.

   @Autowired
   JobRegistry jobRegistry;

   @Bean
   public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor() {
       JobRegistryBeanPostProcessor postProcessor = new JobRegistryBeanPostProcessor();
       postProcessor.setJobRegistry(jobRegistry);
       return postProcessor;
   }
Sign up to request clarification or add additional context in comments.

Comments

5

The JobOperator requires a JobLocator to locate jobs to restart, stop, etc. This JobLocator (typically a MapJobRegistry) should be populated with known jobs, and this should be done either manually or by adding a JobRegistryBeanPostProcessor to the application context.

This is explained in the reference documentation here: JobRegistry.

Comments

0

You can also trigger job using jobLauncher. Here is a blog explaining it.

In short you can refer to this code.

@Component
public class JobScheduler
{
  @Autowired
  JobLauncher jobLauncher;
   
  @Qualifier("jobBeanName") // if you have multiple jobs
  @Autowired
  Job job;
   
  @Scheduled(cron = "* * * * * *")
  public void runJob() {
    jobLauncher.run(job, new JobParameters());
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.