Parallel spring batch jobs mixing up data
23:55 28 Feb 2026

Hi this one is really puzzling me. I am trying to run a separate instance of a spring batch job for every file, up to 20 at a time.

I've created a stripped down job of how im using it to reproduce the issue. This is how I invoke the jobs via main class:

public class Main implements CommandLineRunner {
    private final JobLauncher jobLauncher;
    private final Job jobConfig;
    private int parallelism = 20;

    public static void main(String[] args) {SpringApplication.run(Main.class, args);}

    @Override
    public void run(String... args) throws Exception {
        File[] files = getFiles();

        ExecutorService pool = Executors.newFixedThreadPool(parallelism);
        List> futures = new ArrayList<>(files.length);

        for (int i = 0; i < files.length; i++) {
            final File file = files[i];

            futures.add(pool.submit(() -> {
                try {
                    JobParameters params = new JobParametersBuilder()
                            .addString("fileName", file.getCanonicalPath(), true)
                            .addString("guid", UUID.randomUUID().toString(), true)
                            .toJobParameters();
                    JobExecution exec = jobLauncher.run(jobConfig, params);
                    return exec.getExitStatus();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }));
        }
        for (Future f : futures) {
            f.get();
        }
        pool.shutdown();
    }

    public static File[]  getFiles() {
        File currentDir = new File("C:\\Code\\spring-batch\\input");
        File[] files = currentDir.listFiles((dir, name) -> name.endsWith(".csv"));
        return files;
    }

And here is the job. All it's doing is creating an output file based upon the inputFile name.

@Configuration
@RequiredArgsConstructor
public class JobConfig {

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new ResourcelessTransactionManager();
    }

    @Bean
    public JobLauncher jobLauncher(JobRepository jobRepository) throws Exception {
        TaskExecutorJobLauncher launcher = new TaskExecutorJobLauncher();
        launcher.setJobRepository(jobRepository);
        launcher.setTaskExecutor(new org.springframework.core.task.SyncTaskExecutor());
        launcher.afterPropertiesSet();
        return launcher;
    }
    @Bean
    public Job simpleJob(JobRepository jobRepository, Step simpleStep) {
        return new JobBuilder("simpleJob", jobRepository)
                .incrementer(new RunIdIncrementer())
                .start(simpleStep)
                .build();
    }

    @Bean
    public Step simpleStep(JobRepository jobRepository,
                           PlatformTransactionManager transactionManager,
                           ItemReader reader,
                           ItemProcessor processor,
                           FlatFileItemWriter writer) {

        return new StepBuilder("simpleStep", jobRepository)
                .chunk(100, transactionManager)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .stream(writer)
                .build();
    }

    @Bean
    @StepScope
    public FlatFileItemReader reader(
            @Value("#{jobParameters['fileName']}") String fileName,
            @Value("#{jobParameters['guid']}") String guid) {

        return new FlatFileItemReaderBuilder()
                .name("reader-" + guid)
                .resource(new FileSystemResource(fileName))
                .lineMapper((line, lineNumber) -> line)
                .build();
    }

    @Bean
    public ItemProcessor processor() {
        return item -> item.toUpperCase();
    }


    @Bean
    @StepScope
    public FlatFileItemWriter writer(
            @Value("#{jobParameters['fileName']}") String fileName,
            @Value("#{jobParameters['guid']}") String guid) {

        String outputName = "OUTPUT_" + getFileNameWithoutExtension(fileName) + "_" + ".out";

        return new FlatFileItemWriterBuilder()
                .name("writer-" + guid)
                .resource(new FileSystemResource(outputName))
                .lineAggregator(new PassThroughLineAggregator<>())
                .build();
    }

    public static String getFileNameWithoutExtension(String fileName) {
      String filename = java.nio.file.Paths.get(fileName).getFileName().toString();
      int dotIndex = filename.lastIndexOf('.');
      if (dotIndex > 0) {
        return filename.substring(0, dotIndex);
      }
      return fileName;
    }
}

I can confirm that this returns one of each CSV file, there are no duplicates and the File[] array is unique. The problem is, somehow the joblauncher is launching instances with the exact same file name and guid. Here's my output, you can see there are several filenames launched multiple times with the same UUID (ex_13.csv, ex_19.csv)

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-20] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_18.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=78696daa-4df3-473f-87cf-42b9a7dc1169, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-4] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_12.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=94a99043-91e6-4466-87e1-b70683e0ab5b, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-5] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_13.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=f9c2ecae-f68a-4c79-a5ef-4af7e0f3930c, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-15] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_13.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=f9c2ecae-f68a-4c79-a5ef-4af7e0f3930c, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-1] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_1.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=1c21c4a5-4956-4fcf-8cce-868ab1bf78cb, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-8] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_16.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=27042f9d-f963-4d96-ad6e-b5dabe18ad2e, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-7] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_15.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=ef576a4e-d225-4eb2-91a4-b3fb1d8b562d, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-3] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_11.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=1b596d93-4311-44e7-9251-84f8eaa9ba21, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-13] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_20.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=18bde259-67ea-4c0d-a20d-3c82b654019b, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-18] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_7.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=e8885719-be1e-4190-996b-011d77cc015b, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-10] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_18.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=78696daa-4df3-473f-87cf-42b9a7dc1169, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-9] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_19.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=f818a9c9-65c2-4fae-b4d4-0f39c0b79a3f, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-17] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_10.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=c47e6895-3ab0-483e-bc2a-adbd334bd33e, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-11] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_19.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=f818a9c9-65c2-4fae-b4d4-0f39c0b79a3f, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-2] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_10.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=c47e6895-3ab0-483e-bc2a-adbd334bd33e, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-19] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_8.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=1bc84fd7-4cf3-4163-a406-2edbcd297045, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-16] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_5.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=5166ebc1-5e03-4d25-a332-9a04cbc2530b, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-12] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_10.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=c47e6895-3ab0-483e-bc2a-adbd334bd33e, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [pool-2-thread-6] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_8.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=1bc84fd7-4cf3-4163-a406-2edbcd297045, type=class java.lang.String, identifying=true}}]

2026-02-28T23:15:53.606-05:00 INFO 16316 --- [ool-2-thread-14] o.s.b.c.l.s.TaskExecutorJobLauncher : Job: [SimpleJob: [name=simpleJob]] launched with the following parameters: [{JobParameter{name='fileName', value=C:\Code\spring-batch\input\ex_3.csv, type=class java.lang.String, identifying=true},JobParameter{name='guid', value=1bb5fea1-333f-4bba-b6c7-ece83149bd18, type=class java.lang.String, identifying=true}}]

java spring spring-batch