RESOLVED - issue BATCH-1522: Intermittent failure of FaultTolerantStepFactoryBean in multi-threaded test

This commit is contained in:
dsyer
2010-03-03 12:48:58 +00:00
parent 17daf7ab07
commit 4aaa88b76d
6 changed files with 287 additions and 18 deletions

View File

@@ -27,8 +27,8 @@ import org.springframework.util.Assert;
/**
* Batch domain object representation the execution of a step. Unlike
* {@link JobExecution}, there are additional properties related the
* processing of items such as commit count, etc.
* {@link JobExecution}, there are additional properties related the processing
* of items such as commit count, etc.
*
* @author Lucas Ward
* @author Dave Syer
@@ -507,8 +507,9 @@ public class StepExecution extends Entity {
return super.toString()
+ String.format(
", name=%s, status=%s, exitStatus=%s, readCount=%d, filterCount=%d, writeCount=%d readSkipCount=%d, writeSkipCount=%d"
+ ", processSkipCount=%d, commitCount=%d, rollbackCount=%d", stepName, status, exitStatus.getExitCode(),
readCount, filterCount, writeCount, readSkipCount, writeSkipCount, processSkipCount, commitCount, rollbackCount);
+ ", processSkipCount=%d, commitCount=%d, rollbackCount=%d", stepName, status,
exitStatus.getExitCode(), readCount, filterCount, writeCount, readSkipCount, writeSkipCount,
processSkipCount, commitCount, rollbackCount);
}
}

View File

@@ -20,6 +20,8 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
@@ -55,6 +57,8 @@ import org.springframework.util.Assert;
*/
public class SimpleJobRepository implements JobRepository {
private static final Log logger = LogFactory.getLog(SimpleJobRepository.class);
private JobInstanceDao jobInstanceDao;
private JobExecutionDao jobExecutionDao;
@@ -238,6 +242,7 @@ public class SimpleJobRepository implements JobRepository {
JobExecution jobExecution = stepExecution.getJobExecution();
jobExecutionDao.synchronizeStatus(jobExecution);
if (jobExecution.isStopping()) {
logger.info("Parent JobExecution is stopped, so passing message on to StepExecution");
stepExecution.setTerminateOnly();
}
}

View File

@@ -307,6 +307,8 @@ public class TaskletStep extends AbstractStep {
private Integer oldVersion;
private boolean locked = false;
public ChunkTransactionCallback(ChunkContext chunkContext) {
this.chunkContext = chunkContext;
this.stepExecution = chunkContext.getStepContext().getStepExecution();
@@ -322,10 +324,16 @@ public class TaskletStep extends AbstractStep {
}
}
if (status == TransactionSynchronization.STATUS_UNKNOWN) {
logger.error("Rolling back with transaction in unknown state");
rollback(stepExecution);
stepExecution.upgradeStatus(BatchStatus.UNKNOWN);
stepExecution.setTerminateOnly();
}
// Only release the lock if we acquired it, and release as late as possible
if (locked) {
semaphore.release();
}
locked = false;
}
public Object doInTransaction(TransactionStatus status) {
@@ -338,8 +346,6 @@ public class TaskletStep extends AbstractStep {
chunkListener.beforeChunk();
boolean locked = false;
try {
try {
@@ -367,9 +373,11 @@ public class TaskletStep extends AbstractStep {
locked = true;
}
catch (InterruptedException e) {
logger.error("Thread interrupted while locking for repository update");
stepExecution.setStatus(BatchStatus.STOPPED);
stepExecution.setTerminateOnly();
Thread.currentThread().interrupt();
throw e;
}
// In case we need to push it back to its old value
@@ -396,6 +404,7 @@ public class TaskletStep extends AbstractStep {
catch (Exception e) {
// If we get to here there was a problem saving the step
// execution and we have to fail.
logger.error("JobRepository failure forcing exit with unknown status", e);
stepExecution.upgradeStatus(BatchStatus.UNKNOWN);
stepExecution.setTerminateOnly();
throw e;
@@ -419,13 +428,6 @@ public class TaskletStep extends AbstractStep {
// Allow checked exceptions
throw new TransactionException(e);
}
finally {
// only release the lock if we acquired it
if (locked) {
semaphore.release();
}
locked = false;
}
return result;