Reputation: 399
I have spring batch job application which parse many csv file containing User details. To parse User details I have a LineMapper which parse from csv file.
So first master step reader reads all file from location and then using Partitioner I have slave steps. All slave steps parallel executed. These slave steps parse each file for User details row by row. After processing it moves processed file to Processed folder.
During testing I kept some wrong value in a file which is causing FlatFileParseException by reader of slave step. Here I would like to move this file to another folder like Failed folder. But I am not able to do this.
How I should write files to Failed folder if any slave step reader fails to parse?
I am using Spring Boot, Spring Batch annotation based
Errors:
FlatFileParseException: Parsing error at line: 10 in resource
JobExecutionException: Partition handler returned an unsuccessful step
Code:
BatchConfiguration.java
@Bean(name = "partitionerJob")
public Job partitionerJob()
throws UnexpectedInputException, MalformedURLException, ParseException {
return jobs.get("partitioningJob")
.start(partitionStep())
.build();
}
@Bean
public Step partitionStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("partitionStep")
.partitioner("slaveStep", partitioner())
.step(slaveStep())
.taskExecutor(taskExecutor())
.build();
}
@Bean
public CustomMultiResourcePartitioner partitioner() {
CustomMultiResourcePartitioner partitioner
= new CustomMultiResourcePartitioner();
Resource[] resources;
try {
resources = resoursePatternResolver
.getResources("file:src/main/resources/input/*.csv");
} catch (IOException e) {
throw new RuntimeException("I/O problems when resolving"
+ " the input file pattern.", e);
}
partitioner.setResources(resources);
return partitioner;
}
@StepScope
@Bean
public FlatFileItemReader<Transaction> itemReader(
@Value("#{stepExecutionContext[fileName]}") String filename)
throws UnexpectedInputException, ParseException {
return new UserDetailReader(fileName);
}
@Bean
@StepScope
public ItemWriter<Transaction> itemWriter(Marshaller
marshaller ,
@Value("#{stepExecutionContext[opFileName]}") String
filename )
throws MalformedURLException {
return new UserDetailWriter(fileName);
}
@Bean
public Step slaveStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("slaveStep").<User, User>chunk(5)
.reader(itemReader(null))
.writer(itemWriter(marshaller(), null))
.build();
}
CustomMultiResourcePartitioner.java
public class CustomMultiResourcePartitioner implements Partitioner {
@Override
public Map<String, ExecutionContext> partition(int gridSize) {
Map<String, ExecutionContext> map = new HashMap<>(gridSize);
int i = 0, k = 1;
for (Resource resource : resources) {
ExecutionContext context = new ExecutionContext();
Assert.state(resource.exists(), "Resource does not exist: "
+ resource);
context.putString(keyName, resource.getFilename());
context.putString("opFileName",
"output"+k+++".xml");
map.put(PARTITION_KEY + i, context);
i++;
}
return map;
}
}
Thanks for help
Upvotes: 1
Views: 1890
Reputation: 11055
You can use skip & skipLimit attributes while defining your step.
Below is sample configuration. Now your slave Step will not fail until the skipLimit is reached.
@Bean
public Step slaveStep()
throws UnexpectedInputException, MalformedURLException, ParseException {
return steps.get("slaveStep").<User, User>chunk(5)
.reader(itemReader(null))
.writer(itemWriter(marshaller(), null))
.faultTolerant()
.skip(Exception.class)
.skipLimit(500)
.build();
}
Move the file to Failed folder
You can define StepExecutionListener for your slaveStep.
in after step method you can get All FailureExceptions
for that step.
Using that you can put your logic for moving file
Sample code
public class MyStepListener implements StepExecutionListener {
@Override
public void beforeStep(StepExecution stepExecution) {
LOGGER.info("MyStepListener beforeStep "+ stepExecution.getSummary());
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
List<Throwable> failureExceptions = stepExecution.getFailureExceptions();
// move file from one folder to another
return null;
}
}
Upvotes: 1