Spring Batch并行作业重复使用相同参数(文件名+UUID)问题排查求助
Spring Batch并行作业重复使用相同参数(文件名+UUID)问题排查求助
我现在想为每个文件单独启动一个Spring Batch作业实例,最多同时运行20个。但奇怪的是,作业会重复使用相同的参数(同一个文件名+同一个UUID),明明每个参数应该都是唯一的。想问问大家可能是什么原因导致UUID和文件名被重复使用?
我已经写了一个简化版的代码来复现这个问题,下面是我的实现:
主调用类代码
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<Future<?>> 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; } }
Spring Batch作业配置类
@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<String> reader, ItemProcessor<String, String> processor, FlatFileItemWriter<String> writer) { return new StepBuilder("simpleStep", jobRepository) .<String, String>chunk(100, transactionManager) .reader(reader) .processor(processor) .writer(writer) .stream(writer) .build(); } @Bean @StepScope public FlatFileItemReader<String> reader( @Value("#{jobParameters['fileName']}") String fileName, @Value("#{jobParameters['guid']}") String guid) { return new FlatFileItemReaderBuilder<String>() .name("reader-" + guid) .resource(new FileSystemResource(fileName)) .lineMapper((line, lineNumber) -> line) .build(); } @Bean public ItemProcessor<String, String> processor() { return item -> item.toUpperCase(); } @Bean @StepScope public FlatFileItemWriter<String> writer( @Value("#{jobParameters['fileName']}") String fileName, @Value("#{jobParameters['guid']}") String guid) { String outputName = "OUTPUT_" + getFileNameWithoutExtension(fileName) + "_" + ".out"; return new FlatFileItemWriterBuilder<String>() .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; } }
问题现象日志
我已经确认getFiles()返回的文件数组里没有重复的文件,但日志里能看到同一个文件名和UUID被多次用于作业启动,比如ex_13.csv对应的UUIDf9c2ecae-f68a-4c79-a5ef-4af7e0f3930c被启动了两次:
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}}\]
备注:内容来源于stack exchange,提问作者oe a
相关产品推荐
相关产品推荐

