1
votes

I am trying to use Spring Batch for jobs. I have two jobs tempJob and tempJob2 in two separate configurations. When try to run the tempJob using commandline arguments(-Dspring.batch.job.names=tempJob), SpringBatch tries to run the tempJob twice and i get following error

2018-06-15 11:36:37.956 INFO 14436 --- [ main] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=tempJob]] completed with the following parameters: [{TimeStamp=06152018 11:36:30}] and the following status: [COMPLETED] 2018-06-15 11:36:38.049 INFO 14436 --- [ main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2018-06-15 11:36:38.058 ERROR 14436 --- [ main] o.s.boot.SpringApplication
: Application run failed

java.lang.IllegalStateException: Failed to execute CommandLineRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:800) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:781) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1255) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1243) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] at com.example.springbatchdemo.SpringbatchdemoApplication.main(SpringbatchdemoApplication.java:22) [classes/:na] Caused by: org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException: A job instance already exists and is complete for parameters={TimeStamp=06152018 11:36:30}. If you want to run this job again, change the parameters. at org.springframework.batch.core.repository.support.SimpleJobRepository.createJobExecution(SimpleJobRepository.java:130) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60] at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60] at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:197) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294) ~[spring-tx-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.batch.core.repository.support.AbstractJobRepositoryFactoryBean$1.invoke(AbstractJobRepositoryFactoryBean.java:181) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.0.7.RELEASE.jar:5.0.7.RELEASE] at com.sun.proxy.$Proxy48.createJobExecution(Unknown Source) ~[na:na] at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:131) ~[spring-batch-core-4.0.1.RELEASE.jar:4.0.1.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:163) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeRegisteredJobs(JobLauncherCommandLineRunner.java:148) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:135) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:128) ~[spring-boot-autoconfigure-2.0.3.RELEASE.jar:2.0.3.RELEASE] at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:797) [spring-boot-2.0.3.RELEASE.jar:2.0.3.RELEASE] ... 5 common frames omitted

2018-06-15 11:36:38.060 INFO 14436 --- [ main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@770c2e6b: startup date [Fri Jun 15 11:36:31 EDT 2018]; root of context hierarchy 2018-06-15 11:36:38.061 INFO 14436 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase -2147482648 2018-06-15 11:36:38.062 INFO 14436 --- [ main] ory$ResourceAnnotationApplicationContext : Closing ResourceAnnotationApplicationContext:com.example.springbatchdemo.config.TempConfig 2018-06-15 11:36:38.063 INFO 14436 --- [ main] ory$ResourceAnnotationApplicationContext : Closing ResourceAnnotationApplicationContext:com.example.springbatchdemo.config.TempConfig2 2018-06-15 11:36:38.064 INFO 14436 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown 2018-06-15 11:36:38.065 INFO 14436 --- [
main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans 2018-06-15 11:36:38.065 INFO 14436 --- [
main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2018-06-15 11:36:38.098 INFO 14436 --- [
main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.

Following are my Spring Batch configurations This is my main class

@SpringBootApplication
@EnableBatchProcessing(modular=true)
public class SpringbatchdemoApplication {

    public static void main(String[] args) {
        String[] params = addTimestampAsParameter(args);
        SpringApplication.run(SpringbatchdemoApplication.class, params);
    }

     @Bean
     public ApplicationContextFactory runTempJob1() {
        return new GenericApplicationContextFactory(TempConfig.class);
     }

     @Bean
     public ApplicationContextFactory runTempJob2() {
        return new GenericApplicationContextFactory(TempConfig2.class);
     }


    public static String[] addTimestampAsParameter(final String[] args){
        String[] params = null;
        if(null != args){
            params = new String[args.length+1];
            for(int i=0;i<args.length;i++){
                params[i]=args[i];
            }
        }else{
            params = new String[1];
        }
        SimpleDateFormat sdf = new SimpleDateFormat("MMddyyyy hh:mm:ss");
        String timeStamp = sdf.format(new Date());
        params[params.length-1] = String.format("TimeStamp=%s", timeStamp);
        return params;
    }
}

Following are my configuration class

@Configuration
public class TempConfig {

    @Autowired
    JobBuilderFactory jobBuilder;

    @Autowired
    StepBuilderFactory stepBuilder;

    @Bean
    public Tasklet sampleTask(){
        return new Tasklet() {

            @Override
            public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {
                System.out.println("Executed Temp Step of TempConfig Job -> TempJob");
                return RepeatStatus.FINISHED;
            }
        };
    }

    @Bean
    public Step tempStep(Tasklet sampleTask){
        return stepBuilder.get("tempStep").tasklet(sampleTask).build();
    }

    @Bean
    public Job tempJob(){
        return jobBuilder.get("tempJob")
        .start(tempStep(null))
        .build();
    }

}

and the second Job configuration

@Configuration
    public class TempConfig2 {

        @Autowired
        JobBuilderFactory jobBuilder;

        @Autowired
        StepBuilderFactory stepBuilder;
        @Bean
        public Step tempStep1(){
            return stepBuilder.get("tempStep1").tasklet(new Tasklet() {

                @Override
                public RepeatStatus execute(StepContribution arg0, ChunkContext arg1) throws Exception {
                    System.out.println("Executed Temp Step of TempConfig2 Job -> TempJob1");
                    return RepeatStatus.FINISHED;
                }
            }).build();
        }

        @Bean
        public Job tempJob1(){
            return jobBuilder.get("tempJob1")
            .start(tempStep1())
            .build();
        }

    }

When I researched further I found out, on giving -Dspring.batch.job.names SpringBatch uses JobLauncherCommandLineRunner.launchJobFromProperties() method to execute jobs. This method tries execute jobs using executeLocalJobs(jobParameters) and executeRegisteredJobs(jobParameters); On debug I found my job was being executed by both methods.

Is there any solution to run job only once using command line parameters with (modular=true). Please help and inform if you need any more information.

1
Did you get resolution for the above said issue ? - Jeff Cook
@Sayali: No I have not found any solution. As a work around, I have commented (modular=true) and developers are ensuring that we do not have same Job or Step name in our code. Please inform me if you find a better workaround or solution. - Akhil Khandelwal

1 Answers

0
votes

As @akhil-khandelwal said, removing (modular=true) from @EnableBatchProcessing annotation can solve the problem. It solved for me.