BATCH-798: Samples working again. TODO: refactor rollbackClassifier into the stateless execution API
This commit is contained in:
@@ -33,6 +33,7 @@ import org.springframework.batch.retry.policy.MapRetryContextCache;
|
||||
import org.springframework.batch.retry.policy.RetryContextCache;
|
||||
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
|
||||
import org.springframework.batch.retry.support.RetryTemplate;
|
||||
import org.springframework.batch.support.Classifier;
|
||||
|
||||
/**
|
||||
* Factory bean for step that provides options for configuring skip behaviour.
|
||||
@@ -225,6 +226,12 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
|
||||
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||
}
|
||||
retryTemplate.setRetryPolicy(retryPolicy);
|
||||
Classifier<Throwable, Boolean> rollbackClassifier = new Classifier<Throwable, Boolean>() {
|
||||
public Boolean classify(Throwable classifiable) {
|
||||
return getTransactionAttribute().rollbackOn(classifiable);
|
||||
}
|
||||
};
|
||||
retryTemplate.setRollbackClassifier(rollbackClassifier);
|
||||
|
||||
// Co-ordinate the retry policy with the exception handler:
|
||||
RepeatOperations stepOperations = getStepOperations();
|
||||
@@ -254,7 +261,7 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
|
||||
ItemSkipPolicy writeSkipPolicy = new LimitCheckingItemSkipPolicy(skipLimit, exceptions,
|
||||
new ArrayList<Class<? extends Throwable>>(fatalExceptionClasses));
|
||||
ChunkOrientedTasklet<T, S> tasklet = new StatefulRetryTasklet<T, S>(getItemReader(), getItemProcessor(),
|
||||
getItemWriter(), getChunkOperations(), retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
getItemWriter(), getChunkOperations(), retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
tasklet.setListeners(getListeners());
|
||||
|
||||
step.setTasklet(tasklet);
|
||||
@@ -297,6 +304,8 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
|
||||
|
||||
final private ItemSkipPolicy processSkipPolicy;
|
||||
|
||||
final private Classifier<Throwable, Boolean> rollbackClassifier;
|
||||
|
||||
/**
|
||||
* @param itemReader
|
||||
* @param itemWriter
|
||||
@@ -304,10 +313,11 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
|
||||
*/
|
||||
public StatefulRetryTasklet(ItemReader<? extends T> itemReader,
|
||||
ItemProcessor<? super T, ? extends S> itemProcessor, ItemWriter<? super S> itemWriter,
|
||||
RepeatOperations chunkOperations, RetryOperations retryTemplate, ItemSkipPolicy readSkipPolicy,
|
||||
RepeatOperations chunkOperations, RetryOperations retryTemplate, Classifier<Throwable, Boolean> rollbackClassifier, ItemSkipPolicy readSkipPolicy,
|
||||
ItemSkipPolicy writeSkipPolicy, ItemSkipPolicy processSkipPolicy) {
|
||||
super(itemReader, itemProcessor, itemWriter, chunkOperations);
|
||||
this.retryOperations = retryTemplate;
|
||||
this.rollbackClassifier = rollbackClassifier;
|
||||
this.readSkipPolicy = readSkipPolicy;
|
||||
this.writeSkipPolicy = writeSkipPolicy;
|
||||
this.processSkipPolicy = processSkipPolicy;
|
||||
@@ -472,7 +482,9 @@ public class SkipLimitStepFactoryBean<T, S> extends SimpleStepFactoryBean<T, S>
|
||||
}
|
||||
catch (Exception e) {
|
||||
checkSkipPolicy(contribution, iterator, e);
|
||||
throw e;
|
||||
if (rollbackClassifier.classify(e)) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@ package org.springframework.batch.core.repository.dao;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.batch.retry.policy.NeverRetryPolicy;
|
||||
import org.springframework.batch.retry.support.RetryTemplate;
|
||||
import org.springframework.batch.support.Classifier;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -84,6 +85,12 @@ public class StatefulRetryTaskletTests {
|
||||
};
|
||||
|
||||
private RetryTemplate retryTemplate = new RetryTemplate();
|
||||
|
||||
private Classifier<Throwable, Boolean> rollbackClassifier = new Classifier<Throwable, Boolean>() {
|
||||
public Boolean classify(Throwable classifiable) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private ItemSkipPolicy readSkipPolicy = new ItemSkipPolicy() {
|
||||
public boolean shouldSkip(Throwable t, int skipCount) throws SkipLimitExceededException {
|
||||
@@ -105,7 +112,7 @@ public class StatefulRetryTaskletTests {
|
||||
@Test
|
||||
public void testBasicHandle() throws Exception {
|
||||
handler = new StatefulRetryTasklet<Integer, String>(itemReader, itemProcessor, itemWriter, chunkOperations,
|
||||
retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
|
||||
handler.execute(contribution, new BasicAttributeAccessor());
|
||||
assertEquals(limit, contribution.getItemCount());
|
||||
@@ -117,7 +124,7 @@ public class StatefulRetryTaskletTests {
|
||||
public Integer read() throws Exception, UnexpectedInputException, NoWorkFoundException, ParseException {
|
||||
throw new RuntimeException("Barf!");
|
||||
}
|
||||
}, itemProcessor, itemWriter, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
}, itemProcessor, itemWriter, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(1));
|
||||
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
|
||||
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
|
||||
@@ -139,7 +146,7 @@ public class StatefulRetryTaskletTests {
|
||||
written.addAll(items);
|
||||
throw new RuntimeException("Barf!");
|
||||
}
|
||||
}, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
}, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(1));
|
||||
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
|
||||
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
|
||||
@@ -165,7 +172,7 @@ public class StatefulRetryTaskletTests {
|
||||
written.addAll(items);
|
||||
throw new RuntimeException("Barf!");
|
||||
}
|
||||
}, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
}, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(2));
|
||||
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
|
||||
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
|
||||
@@ -217,7 +224,7 @@ public class StatefulRetryTaskletTests {
|
||||
throw new RuntimeException("Barf!");
|
||||
}
|
||||
}
|
||||
, itemWriter, chunkOperations, retryTemplate, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
, itemWriter, chunkOperations, retryTemplate, rollbackClassifier, readSkipPolicy, writeSkipPolicy, writeSkipPolicy);
|
||||
chunkOperations.setCompletionPolicy(new SimpleCompletionPolicy(2));
|
||||
StepContribution contribution = new StepExecution("foo", null).createStepContribution();
|
||||
BasicAttributeAccessor attributes = new BasicAttributeAccessor();
|
||||
|
||||
@@ -448,6 +448,8 @@ public class RetryTemplate implements RetryOperations {
|
||||
protected boolean shouldRethrow(RetryPolicy retryPolicy, RetryContext context, RetryState state) {
|
||||
// Allow stateless behaviour to take over for certain exception types
|
||||
if (rollbackClassifier != null) {
|
||||
// TODO: remove this. Make it part of the stateful execution parameters?
|
||||
// Then we wouldn't have to make assertions about the stateless case.
|
||||
boolean rollback = rollbackClassifier.classify(context.getLastThrowable());
|
||||
if (rollback && state == null && retryPolicy.canRetry(context)) {
|
||||
throw new RetryException("Inconsistent configuration. The retry policy says we can retry but "
|
||||
|
||||
@@ -28,6 +28,7 @@ public class ItemTrackingItemWriter<T> implements ItemWriter<T> {
|
||||
counter += items.size();
|
||||
if (current < failure && counter >= failure) {
|
||||
failed = items.get(failure-current-1);
|
||||
this.items.remove(failed);
|
||||
throw new ValidationException("validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,10 @@ public class ItemTrackingItemWriterTests {
|
||||
catch (ValidationException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(3, writer.getItems().size());
|
||||
// the failed item is removed
|
||||
assertEquals(2, writer.getItems().size());
|
||||
writer.write(Arrays.asList("a", "e", "c"));
|
||||
assertEquals(6, writer.getItems().size());
|
||||
assertEquals(5, writer.getItems().size());
|
||||
try {
|
||||
writer.write(Arrays.asList("f", "b", "g"));
|
||||
fail("Expected ValidationException");
|
||||
@@ -61,7 +62,8 @@ public class ItemTrackingItemWriterTests {
|
||||
catch (ValidationException e) {
|
||||
// expected
|
||||
}
|
||||
assertEquals(6, writer.getItems().size());
|
||||
// barf immediately if a failure is detected
|
||||
assertEquals(5, writer.getItems().size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user