spring-projects / spring-projects/spring-batch

Multiple jobs running with same parameters

Open
#4,667 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status: waiting-for-triage type: bug
Dominant language
Java
Stars
3k
Forks
2.5k
Avg merge
6d 53m
Merged PRs (30d)
3

Description

Bug description
I have multiple instances of the application running so the job gets triggered multiple times but I want only one job to actually run.
I have provided the same job parameters.
The time param is based on the hour but still I can see that 3 jobs are getting created and running at the time.
Also when the job fails I have a job operator restart logic which also fails with the error that 3 instance are running.
I have added the error log below.

Environment
<spring.boot.version>3.3.3</spring.boot.version>
<spring-core.version>6.1.12</spring-core.version>
<spring.batch.version>5.1.2</spring.batch.version>

Steps to reproduce
Code for launching the job-
lastJobExecution = launcher.run(job, jobParameters);
JobParameters jobParameters = new JobParametersBuilder()
.addLong("run.id", 1L)
.addString("TENANTID", tenantId)
.addString("MODE", mode)
.addString("PARAM_TIME", getCurrentTimeInHour())
.toJobParameters();
return jobParameters;

String getCurrentTimeInHour() {
LocalDateTime currentTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH");
return currentTime.format(formatter);
}

@Bean(name = "JobRepository1")
public JobRepository jobRepository1() throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(ds);
factory.setTransactionManager(transactionManager); [PlatformTransactionManager]
factory.afterPropertiesSet();
return factory.getObject();
}

@Bean(name = "launcher1")
public JobLauncher jobLauncher() throws Exception {
TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
jobLauncher.setJobRepository(jobRepository1());
jobLauncher.setTaskExecutor(simpleAsyncTaskExecutor());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}

Errors faced-
{"msg":"Unexpected error running the task "{}"","level":"ERROR","written_ts":"1726852080036217710","logger":".jobs.TriggerFactory","exception_type":"java.lang.IllegalStateException","written_at":"2024-09-20T17:08:00.035Z","thread":"scheduling-1","type":"log","exception_message":"instance count must be 1 but was 3","stacktrace":["java.lang.IllegalStateException: instance count must be 1 but was 3","\tat org.springframework.util.Assert.state(Assert.java:76)","\tat org.springframework.batch.core.repository.dao.JdbcJobInstanceDao.getJobInstance(JdbcJobInstanceDao.java:193)","\tat org.springframework.batch.core.repository.support.SimpleJobRepository.getLastJobExecution(SimpleJobRepository.java:299)","\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)","\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)","\tat java.base/java.lang.reflect.Method.invoke(Method.java:569)","\tat org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:355)","\tat org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)","\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)","\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:379)","\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)","\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)","\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:223)","\tat jdk.proxy2/jdk.proxy2.$Proxy140.getLastJobExecution(Unknown Source)","\tat org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:111)","\tat org.springframework.batch.core.launch.support.TaskExecutorJobLauncher.run(TaskExecutorJobLauncher.java:59)","\tat apim.anomaly.scheduling.jobs.TriggerTrainingFactory.buildTraining(TriggerTrainingFactory.java:117)","\tat apim.anomaly.scheduling.jobs.TriggerTrainingFactory.runTrainings(TriggerTrainingFactory.java:56)","\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)","\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)","\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)","\tat java.base/java.lang.reflect.Method.invoke(Method.java:569)","\tat org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130)","\tat org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124)","\tat io.micrometer.observation.Observation.observe(Observation.java:499)","\tat org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124)","\tat org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)","\tat org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:96)","\tat java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)","\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)","\tat java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)","\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)","\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)","\tat java.base/java.lang.Thread.run(Thread.java:840)"]}

Images of the batch table-
Job name and tenant id is the same for all 3 jobs.

IMG-20240921-WA0001~2
IMG-20240921-WA0002

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with JdbcJobInstanceDao.getJobInstance and SimpleJobRepository.getLastJobExecution in the stack trace, then review the custom JobRepository1 and launcher1 configuration and the TriggerTrainingFactory entry points. Reproduce concurrent launches using the shown parameters and verify that duplicate scheduling does not create multiple instances for the same job parameters.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring-boot
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.