IN PROGRESS - issue BATCH-572: Retryable exceptions cannot be skippable
Modified StatefulRetryStepFactoryBean to use skip listener instead of ItemRecoverer.
This commit is contained in:
@@ -22,12 +22,16 @@ import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.batch.core.listener.SkipListenerSupport;
|
||||
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
|
||||
@@ -35,9 +39,9 @@ import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.item.AbstractItemWriter;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.retry.RetryException;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
@@ -48,13 +52,15 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
*/
|
||||
public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private StatefulRetryStepFactoryBean factory = new StatefulRetryStepFactoryBean();
|
||||
|
||||
private List recovered = new ArrayList();
|
||||
|
||||
private List processed = new ArrayList();
|
||||
|
||||
int count = 0;
|
||||
|
||||
int count = 0;
|
||||
|
||||
private SimpleJobRepository repository = new SimpleJobRepository(new MapJobInstanceDao(), new MapJobExecutionDao(),
|
||||
new MapStepExecutionDao());
|
||||
@@ -72,11 +78,11 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
* @see junit.framework.TestCase#setUp()
|
||||
*/
|
||||
protected void setUp() throws Exception {
|
||||
|
||||
|
||||
MapJobInstanceDao.clear();
|
||||
MapJobExecutionDao.clear();
|
||||
MapStepExecutionDao.clear();
|
||||
|
||||
|
||||
factory.setBeanName("step");
|
||||
|
||||
factory.setItemReader(new ListItemReader(new ArrayList()));
|
||||
@@ -86,10 +92,11 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
JobSupport job = new JobSupport("jobName");
|
||||
job.setRestartable(true);
|
||||
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique").toJobParameters();
|
||||
JobParameters jobParameters = new JobParametersBuilder().addString("statefulTest", "make_this_unique")
|
||||
.toJobParameters();
|
||||
jobExecution = repository.createJobExecution(job, jobParameters);
|
||||
jobExecution.setEndTime(new Date());
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void testType() throws Exception {
|
||||
@@ -100,14 +107,7 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
assertTrue(factory.getObject() instanceof Step);
|
||||
}
|
||||
|
||||
public void testRecovery() throws Exception {
|
||||
factory.setItemRecoverer(new ItemRecoverer() {
|
||||
public Object recover(Object item, Throwable cause) {
|
||||
recovered.add(item);
|
||||
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
|
||||
return item;
|
||||
}
|
||||
});
|
||||
public void testSuccessfulRetry() throws Exception {
|
||||
List items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c" }));
|
||||
ItemReader provider = new ListItemReader(items) {
|
||||
@@ -126,14 +126,15 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
|
||||
|
||||
assertEquals(0, stepExecution.getSkipCount());
|
||||
|
||||
// b is processed twice, plus 1, plus c, plus the null at end
|
||||
assertEquals(5, count);
|
||||
}
|
||||
|
||||
|
||||
public void testSkipAndRetry() throws Exception {
|
||||
factory.setSkippableExceptionClasses(new Class[] {Exception.class});
|
||||
factory.setSkippableExceptionClasses(new Class[] { Exception.class });
|
||||
factory.setSkipLimit(2);
|
||||
List items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
|
||||
@@ -153,46 +154,54 @@ public class StatefulRetryStepFactoryBeanTests extends TestCase {
|
||||
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
|
||||
|
||||
assertEquals(2, stepExecution.getSkipCount());
|
||||
// b is processed once and skipped, plus 1, plus c, plus the null at end
|
||||
assertEquals(7, count);
|
||||
}
|
||||
|
||||
//The following test fails due to current expected behavior of retry
|
||||
//that will be addressed in 1.1
|
||||
// public void testSkipAndRetryWithWriteFailure() throws Exception {
|
||||
//
|
||||
// factory.setSkippableExceptionClasses(new Class[] {RetryException.class});
|
||||
// factory.setSkipLimit(2);
|
||||
// List items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
// items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
|
||||
// ItemReader provider = new ListItemReader(items) {
|
||||
// public Object read() {
|
||||
// Object item = super.read();
|
||||
// System.out.print("Read Called! Item: [" + item + "]");
|
||||
// count++;
|
||||
// return item;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// ItemWriter itemWriter = new AbstractItemWriter(){
|
||||
// public void write(Object item) throws Exception {
|
||||
// System.out.print("Write Called! Item: [" + item + "]");
|
||||
// if ("b".equals(item) || "d".equals(item)) {
|
||||
// throw new RuntimeException("Read error - planned but skippable.");
|
||||
// }
|
||||
// }};
|
||||
// factory.setItemReader(provider);
|
||||
// factory.setItemWriter(itemWriter);
|
||||
// factory.setRetryLimit(5);
|
||||
// factory.setRetryableExceptionClasses(new Class[]{RuntimeException.class});
|
||||
// AbstractStep step = (AbstractStep) factory.getObject();
|
||||
// step.setName("mytest");
|
||||
// StepExecution stepExecution = new StepExecution(step, jobExecution);
|
||||
// step.execute(stepExecution);
|
||||
//
|
||||
// assertEquals(2, stepExecution.getSkipCount());
|
||||
// assertEquals(9, count);
|
||||
// }
|
||||
|
||||
public void testSkipAndRetryWithWriteFailure() throws Exception {
|
||||
|
||||
factory.setSkippableExceptionClasses(new Class[] { RetryException.class });
|
||||
factory.setListeners(new StepListener[] { new SkipListenerSupport() {
|
||||
public void onSkipInWrite(Object item, Throwable t) {
|
||||
recovered.add(item);
|
||||
assertTrue(TransactionSynchronizationManager.isActualTransactionActive());
|
||||
}
|
||||
} });
|
||||
factory.setSkipLimit(2);
|
||||
List items = TransactionAwareProxyFactory.createTransactionalList();
|
||||
items.addAll(Arrays.asList(new String[] { "a", "b", "c", "d", "e", "f" }));
|
||||
ItemReader provider = new ListItemReader(items) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
logger.debug("Read Called! Item: [" + item + "]");
|
||||
count++;
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
ItemWriter itemWriter = new AbstractItemWriter() {
|
||||
public void write(Object item) throws Exception {
|
||||
logger.debug("Write Called! Item: [" + item + "]");
|
||||
if ("b".equals(item) || "d".equals(item)) {
|
||||
throw new RuntimeException("Read error - planned but skippable.");
|
||||
}
|
||||
}
|
||||
};
|
||||
factory.setItemReader(provider);
|
||||
factory.setItemWriter(itemWriter);
|
||||
factory.setRetryLimit(5);
|
||||
factory.setRetryableExceptionClasses(new Class[] { RuntimeException.class });
|
||||
AbstractStep step = (AbstractStep) factory.getObject();
|
||||
step.setName("mytest");
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), jobExecution);
|
||||
step.execute(stepExecution);
|
||||
|
||||
assertEquals(2, recovered.size());
|
||||
assertEquals(2, stepExecution.getSkipCount());
|
||||
assertEquals(2, stepExecution.getWriteSkipCount().intValue());
|
||||
// each item once, plus 5 failed retries each for b and d, plus the null terminator
|
||||
assertEquals(17, count);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user