BATCHADM-72: Improve chunking traceability
- add sequence info to chunks - Improve logging in ChunkMessageChannelItemWriter - Add mysql/h2/derby properties to integration project - Add drop scripts necessary for persistent databases
This commit is contained in:
committed by
Michael Minella
parent
a00fd31172
commit
88638ce05f
@@ -346,6 +346,12 @@
|
||||
<version>1.2.14</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.2.125</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#Fri Sep 03 15:05:09 BST 2010
|
||||
#Fri Sep 17 16:25:48 BST 2010
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/ChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1102" endstart\="1096" start\="901" startend\="967"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n<element type\="job">\n<structure end\="1473" endstart\="1467" start\="1107" startend\="1182"/>\n<bounds height\="118" width\="127" x\="106" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1667" endstart\="1661" start\="1306" startend\="1372"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJdbcIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1937" endstart\="1931" start\="1576" startend\="1642"/>\n<bounds height\="118" width\="82" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJdbcIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1937" endstart\="1931" start\="1576" startend\="1642"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="job">\r\n<structure end\="1767" endstart\="1761" start\="1416" startend\="1482"/>\r\n<bounds height\="118" width\="75" x\="15" y\="17"/>\r\n</element>\r\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1267" endstart\="1261" start\="1065" startend\="1131"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/file/FileToMessagesJobIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="job">\r\n<structure end\="972" endstart\="966" start\="771" startend\="837"/>\r\n<bounds height\="118" width\="75" x\="15" y\="17"/>\r\n</element>\r\n</graph>
|
||||
@@ -9,5 +9,7 @@
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/step/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1419" endstart\="1413" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1953" endstart\="1946" start\="1846" startend\="1916"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/tasklet/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1421" endstart\="1415" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1962" endstart\="1955" start\="1855" startend\="1925"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="2988" endstart\="2988" start\="2951" startend\="2988"/>\n<bounds height\="112" width\="116" x\="19" y\="17"/>\n</element>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="3188" endstart\="3166" start\="3089" startend\="3138"/>\n<bounds height\="112" width\="116" x\="291" y\="17"/>\n</element>\n<element clazz\="ServiceActivatorModelElement" type\="service-activator">\n<structure end\="3293" endstart\="3293" start\="3191" startend\="3293"/>\n<bounds height\="112" width\="116" x\="155" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJdbcIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="3136" endstart\="3114" start\="3022" startend\="3057"/>\n<bounds height\="112" width\="116" x\="19" y\="17"/>\n</element>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="3252" endstart\="3230" start\="3139" startend\="3173"/>\n<bounds height\="112" width\="116" x\="291" y\="17"/>\n</element>\n<element clazz\="ServiceActivatorModelElement" type\="service-activator">\n<structure end\="3551" endstart\="3519" start\="3255" startend\="3355"/>\n<bounds height\="112" width\="116" x\="155" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="outbound-channel-adapter">\r\n<structure end\="2871" endstart\="2871" start\="2747" startend\="2871"/>\r\n<bounds height\="100" width\="155" x\="157" y\="17"/>\r\n</element>\r\n<element type\="channel">\r\n<structure end\="2910" endstart\="2910" start\="2873" startend\="2910"/>\r\n<bounds height\="99" width\="118" x\="19" y\="17"/>\r\n</element>\r\n<element type\="channel">\r\n<structure end\="2949" endstart\="2949" start\="2912" startend\="2949"/>\r\n<bounds height\="99" width\="118" x\="19" y\="137"/>\r\n</element>\r\n<element type\="transformer">\r\n<structure end\="3070" endstart\="3070" start\="2952" startend\="3070"/>\r\n<bounds height\="100" width\="155" x\="157" y\="137"/>\r\n</element>\r\n<element type\="channel">\r\n<structure end\="4339" endstart\="4317" start\="3541" startend\="3590"/>\r\n<bounds height\="99" width\="118" x\="332" y\="137"/>\r\n</element>\r\n<element type\="interceptors">\r\n<structure end\="4315" endstart\="4288" start\="3617" startend\="3643"/>\r\n<bounds height\="53" width\="1" x\="468" y\="129"/>\r\n</element>\r\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/integration\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/retry/RetryTransactionalPollingIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="1431" endstart\="1431" start\="1394" startend\="1431"/>\n<bounds height\="112" width\="116" x\="155" y\="149"/>\n</element>\n<element clazz\="ChannelModelElement" type\="channel">\n<structure end\="1469" endstart\="1469" start\="1433" startend\="1469"/>\n<bounds height\="112" width\="116" x\="19" y\="17"/>\n</element>\n<element clazz\="InboundChannelAdapterModelElement" type\="inbound-channel-adapter">\n<structure end\="1774" endstart\="1736" start\="1472" startend\="1558"/>\n<bounds height\="112" width\="116" x\="19" y\="149"/>\n</element>\n<element clazz\="OutboundChannelAdapterModelElement" type\="outbound-channel-adapter">\n<structure end\="1866" endstart\="1866" start\="1777" startend\="1866"/>\n<bounds height\="112" width\="116" x\="155" y\="17"/>\n</element>\n</graph>
|
||||
eclipse.preferences.version=1
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-batch-integration</artifactId>
|
||||
<name>Spring Batch Integration</name>
|
||||
@@ -68,6 +69,21 @@
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
|
||||
@@ -64,11 +64,9 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
private PollableChannel replyChannel;
|
||||
|
||||
/**
|
||||
* The maximum number of times to wait at the end of a step for a non-null
|
||||
* result from the remote workers. This is a multiplier on the receive
|
||||
* timeout set separately on the gateway. The ideal value is a compromise
|
||||
* between allowing slow workers time to finish, and responsiveness if there
|
||||
* is a dead worker. Defaults to 40.
|
||||
* The maximum number of times to wait at the end of a step for a non-null result from the remote workers. This is a
|
||||
* multiplier on the receive timeout set separately on the gateway. The ideal value is a compromise between allowing
|
||||
* slow workers time to finish, and responsiveness if there is a dead worker. Defaults to 40.
|
||||
*
|
||||
* @param maxWaitTimeouts the maximum number of wait timeouts
|
||||
*/
|
||||
@@ -77,8 +75,8 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the throttle limit. This limits the number of pending
|
||||
* requests for chunk processing to avoid overwhelming the receivers.
|
||||
* Public setter for the throttle limit. This limits the number of pending requests for chunk processing to avoid
|
||||
* overwhelming the receivers.
|
||||
* @param throttleLimit the throttle limit to set
|
||||
*/
|
||||
public void setThrottleLimit(long throttleLimit) {
|
||||
@@ -102,9 +100,10 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
|
||||
if (!items.isEmpty()) {
|
||||
|
||||
logger.debug("Dispatching chunk: " + items);
|
||||
ChunkRequest<T> request = new ChunkRequest<T>(items, localState.getJobId(), localState
|
||||
.createStepContribution());
|
||||
ChunkRequest<T> request = localState.getRequest(items);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Dispatching chunk: " + request);
|
||||
}
|
||||
messagingGateway.send(new GenericMessage<ChunkRequest<T>>(request));
|
||||
localState.incrementExpected();
|
||||
|
||||
@@ -142,9 +141,6 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
}
|
||||
|
||||
for (StepContribution contribution : getStepContributions()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Applying:" + contribution);
|
||||
}
|
||||
stepExecution.apply(contribution);
|
||||
}
|
||||
}
|
||||
@@ -175,12 +171,19 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
}
|
||||
|
||||
public Collection<StepContribution> getStepContributions() {
|
||||
return localState.pollStepContributions();
|
||||
List<StepContribution> contributions = new ArrayList<StepContribution>();
|
||||
for (ChunkResponse response : localState.pollChunkResponses()) {
|
||||
StepContribution contribution = response.getStepContribution();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Applying: " + response);
|
||||
}
|
||||
contributions.add(contribution);
|
||||
}
|
||||
return contributions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until all the results that are in the pipeline come back to the
|
||||
* reply channel.
|
||||
* Wait until all the results that are in the pipeline come back to the reply channel.
|
||||
*
|
||||
* @return true if successfully received a result, false if timed out
|
||||
*/
|
||||
@@ -206,14 +209,12 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next result if it is available (within the timeout specified in
|
||||
* the gateway), otherwise do nothing.
|
||||
* Get the next result if it is available (within the timeout specified in the gateway), otherwise do nothing.
|
||||
*
|
||||
* @throws AsynchronousFailureException If there is a response and it
|
||||
* contains a failed chunk response.
|
||||
* @throws AsynchronousFailureException If there is a response and it contains a failed chunk response.
|
||||
*
|
||||
* @throws IllegalStateException if the result contains the wrong job
|
||||
* instance id (maybe we are sharing a channel and we shouldn't be)
|
||||
* @throws IllegalStateException if the result contains the wrong job instance id (maybe we are sharing a channel
|
||||
* and we shouldn't be)
|
||||
*/
|
||||
private void getNextResult() throws AsynchronousFailureException {
|
||||
Message<ChunkResponse> message = messagingGateway.receive(replyChannel);
|
||||
@@ -235,7 +236,7 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
+ "is probably inconsistent, and the step will fail.");
|
||||
localState.incrementRedelivered();
|
||||
}
|
||||
localState.pushStepContribution(payload.getStepContribution());
|
||||
localState.pushResponse(payload);
|
||||
localState.incrementActual();
|
||||
if (!payload.isSuccessful()) {
|
||||
throw new AsynchronousFailureException("Failure or interrupt detected in handler: "
|
||||
@@ -245,8 +246,8 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-throws the original throwable if it is unchecked, wraps checked
|
||||
* exceptions into {@link AsynchronousFailureException}.
|
||||
* Re-throws the original throwable if it is unchecked, wraps checked exceptions into
|
||||
* {@link AsynchronousFailureException}.
|
||||
*/
|
||||
private static AsynchronousFailureException wrapIfNecessary(Throwable throwable) {
|
||||
if (throwable instanceof Error) {
|
||||
@@ -262,6 +263,8 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
|
||||
private static class LocalState {
|
||||
|
||||
private AtomicInteger current = new AtomicInteger(-1);
|
||||
|
||||
private AtomicInteger actual = new AtomicInteger();
|
||||
|
||||
private AtomicInteger expected = new AtomicInteger();
|
||||
@@ -270,21 +273,25 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
|
||||
private StepExecution stepExecution;
|
||||
|
||||
private Queue<StepContribution> contributions = new LinkedBlockingQueue<StepContribution>();
|
||||
private Queue<ChunkResponse> contributions = new LinkedBlockingQueue<ChunkResponse>();
|
||||
|
||||
public int getExpecting() {
|
||||
return expected.get() - actual.get();
|
||||
}
|
||||
|
||||
public <T> ChunkRequest<T> getRequest(List<? extends T> items) {
|
||||
return new ChunkRequest<T>(current.incrementAndGet(), items, getJobId(), createStepContribution());
|
||||
}
|
||||
|
||||
public void open(int expectedValue, int actualValue) {
|
||||
actual.set(actualValue);
|
||||
expected.set(expectedValue);
|
||||
}
|
||||
|
||||
public Collection<StepContribution> pollStepContributions() {
|
||||
Collection<StepContribution> set = new ArrayList<StepContribution>();
|
||||
public Collection<ChunkResponse> pollChunkResponses() {
|
||||
Collection<ChunkResponse> set = new ArrayList<ChunkResponse>();
|
||||
synchronized (contributions) {
|
||||
StepContribution item = contributions.poll();
|
||||
ChunkResponse item = contributions.poll();
|
||||
while (item != null) {
|
||||
set.add(item);
|
||||
item = contributions.poll();
|
||||
@@ -293,7 +300,7 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
return set;
|
||||
}
|
||||
|
||||
public void pushStepContribution(StepContribution stepContribution) {
|
||||
public void pushResponse(ChunkResponse stepContribution) {
|
||||
synchronized (contributions) {
|
||||
contributions.add(stepContribution);
|
||||
}
|
||||
|
||||
@@ -80,12 +80,12 @@ public class ChunkProcessorChunkHandler<S> implements ChunkHandler<S>, Initializ
|
||||
Throwable failure = process(chunkRequest, stepContribution);
|
||||
if (failure != null) {
|
||||
logger.debug("Failed chunk", failure);
|
||||
return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, failure.getClass().getName()
|
||||
return new ChunkResponse(false, chunkRequest.getSequence(), chunkRequest.getJobId(), stepContribution, failure.getClass().getName()
|
||||
+ ": " + failure.getMessage());
|
||||
}
|
||||
|
||||
logger.debug("Completed chunk handling with " + stepContribution);
|
||||
return new ChunkResponse(true, chunkRequest.getJobId(), stepContribution);
|
||||
return new ChunkResponse(true, chunkRequest.getSequence(), chunkRequest.getJobId(), stepContribution);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ import java.util.Collection;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
|
||||
/**
|
||||
* Encapsulation of a chunk of items to be processed remotely as part of a step execution.
|
||||
* Encapsulation of a chunk of items to be processed remotely as part of a step
|
||||
* execution.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -30,19 +31,22 @@ import org.springframework.batch.core.StepContribution;
|
||||
*/
|
||||
public class ChunkRequest<T> implements Serializable {
|
||||
|
||||
private final Long jobId;
|
||||
private final long jobId;
|
||||
|
||||
private final Collection<? extends T> items;
|
||||
|
||||
private final StepContribution stepContribution;
|
||||
|
||||
public ChunkRequest(Collection<? extends T> items, Long jobId, StepContribution stepContribution) {
|
||||
private final int sequence;
|
||||
|
||||
public ChunkRequest(int sequence, Collection<? extends T> items, long jobId, StepContribution stepContribution) {
|
||||
this.sequence = sequence;
|
||||
this.items = items;
|
||||
this.jobId = jobId;
|
||||
this.stepContribution = stepContribution;
|
||||
}
|
||||
|
||||
public Long getJobId() {
|
||||
public long getJobId() {
|
||||
return jobId;
|
||||
}
|
||||
|
||||
@@ -50,6 +54,10 @@ public class ChunkRequest<T> implements Serializable {
|
||||
return items;
|
||||
}
|
||||
|
||||
public int getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link StepContribution} for this chunk
|
||||
*/
|
||||
@@ -62,8 +70,8 @@ public class ChunkRequest<T> implements Serializable {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": jobId=" + jobId + ", contribution=" + stepContribution + ", item count="
|
||||
+ items.size();
|
||||
return getClass().getSimpleName() + ": jobId=" + jobId + ", sequence=" + sequence + ", contribution="
|
||||
+ stepContribution + ", item count=" + items.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,24 +38,27 @@ public class ChunkResponse implements Serializable {
|
||||
|
||||
private final boolean redelivered;
|
||||
|
||||
public ChunkResponse(Long jobId, StepContribution stepContribution) {
|
||||
this(true, jobId, stepContribution, null);
|
||||
private final int sequence;
|
||||
|
||||
public ChunkResponse(int sequence, Long jobId, StepContribution stepContribution) {
|
||||
this(true, sequence, jobId, stepContribution, null);
|
||||
}
|
||||
|
||||
public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution) {
|
||||
this(status, jobId, stepContribution, null);
|
||||
public ChunkResponse(boolean status, int sequence, Long jobId, StepContribution stepContribution) {
|
||||
this(status, sequence, jobId, stepContribution, null);
|
||||
}
|
||||
|
||||
public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution, String message) {
|
||||
this(status, jobId, stepContribution, message, false);
|
||||
public ChunkResponse(boolean status, int sequence, Long jobId, StepContribution stepContribution, String message) {
|
||||
this(status, sequence, jobId, stepContribution, message, false);
|
||||
}
|
||||
|
||||
public ChunkResponse(ChunkResponse input, boolean redelivered) {
|
||||
this(input.status, input.jobId, input.stepContribution, input.message, redelivered);
|
||||
this(input.status, input.sequence, input.jobId, input.stepContribution, input.message, redelivered);
|
||||
}
|
||||
|
||||
public ChunkResponse(boolean status, Long jobId, StepContribution stepContribution, String message, boolean redelivered) {
|
||||
public ChunkResponse(boolean status, int sequence, Long jobId, StepContribution stepContribution, String message, boolean redelivered) {
|
||||
this.status = status;
|
||||
this.sequence = sequence;
|
||||
this.jobId = jobId;
|
||||
this.stepContribution = stepContribution;
|
||||
this.message = message;
|
||||
@@ -69,6 +72,10 @@ public class ChunkResponse implements Serializable {
|
||||
public Long getJobId() {
|
||||
return jobId;
|
||||
}
|
||||
|
||||
public int getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return status;
|
||||
@@ -87,7 +94,7 @@ public class ChunkResponse implements Serializable {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + ": jobId=" + jobId + ", stepContribution=" + stepContribution
|
||||
return getClass().getSimpleName() + ": jobId=" + jobId + ", sequence=" + sequence + ", stepContribution=" + stepContribution
|
||||
+ ", successful=" + status;
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ public class ChunkMessageItemWriterIntegrationTests {
|
||||
private GenericMessage<ChunkRequest> getSimpleMessage(String string, Long jobId) {
|
||||
StepContribution stepContribution = new JobExecution(new JobInstance(0L, new JobParameters(), "job"), 1L)
|
||||
.createStepExecution("step").createStepContribution();
|
||||
ChunkRequest chunk = new ChunkRequest(StringUtils.commaDelimitedListToSet(string), jobId, stepContribution);
|
||||
ChunkRequest chunk = new ChunkRequest(0, StringUtils.commaDelimitedListToSet(string), jobId, stepContribution);
|
||||
GenericMessage<ChunkRequest> message = new GenericMessage<ChunkRequest>(chunk);
|
||||
return message;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ public class ChunkProcessorChunkHandlerTests {
|
||||
}
|
||||
});
|
||||
StepContribution stepContribution = MetaDataInstanceFactory.createStepExecution().createStepContribution();
|
||||
ChunkResponse response = handler.handleChunk(new ChunkRequest<Object>(StringUtils
|
||||
.commaDelimitedListToSet("foo,bar"), 12L, stepContribution));
|
||||
ChunkResponse response = handler.handleChunk(new ChunkRequest<Object>(0, StringUtils
|
||||
.commaDelimitedListToSet("foo,bar"), 12L, stepContribution));
|
||||
assertEquals(stepContribution, response.getStepContribution());
|
||||
assertEquals(12, response.getJobId().longValue());
|
||||
assertTrue(response.isSuccessful());
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package org.springframework.batch.integration.chunk;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -29,12 +30,12 @@ import org.springframework.batch.test.MetaDataInstanceFactory;
|
||||
*/
|
||||
public class ChunkRequestTests {
|
||||
|
||||
private ChunkRequest<String> request = new ChunkRequest<String>(Arrays.asList("foo", "bar"), 111L,
|
||||
MetaDataInstanceFactory.createStepExecution().createStepContribution());
|
||||
private ChunkRequest<String> request = new ChunkRequest<String>(0, Arrays.asList("foo", "bar"),
|
||||
111L, MetaDataInstanceFactory.createStepExecution().createStepContribution());
|
||||
|
||||
@Test
|
||||
public void testGetJobId() {
|
||||
assertEquals(new Long(111L), request.getJobId());
|
||||
assertEquals(111L, request.getJobId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -58,7 +59,7 @@ public class ChunkRequestTests {
|
||||
ChunkRequest<String> result = (ChunkRequest<String>) SerializationUtils.deserialize(SerializationUtils
|
||||
.serialize(request));
|
||||
assertNotNull(result.getStepContribution());
|
||||
assertEquals(new Long(111L), result.getJobId());
|
||||
assertEquals(111L, result.getJobId());
|
||||
assertEquals(2, result.getItems().size());
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.springframework.batch.test.MetaDataInstanceFactory;
|
||||
*/
|
||||
public class ChunkResponseTests {
|
||||
|
||||
private ChunkResponse response = new ChunkResponse(111L, MetaDataInstanceFactory.createStepExecution()
|
||||
private ChunkResponse response = new ChunkResponse(0, 111L, MetaDataInstanceFactory.createStepExecution()
|
||||
.createStepContribution());
|
||||
|
||||
@Test
|
||||
|
||||
@@ -34,6 +34,9 @@ public class RemoteChunkFaultTolerantStepJdbcIntegrationTests {
|
||||
@Autowired
|
||||
private PollableChannel replies;
|
||||
|
||||
// @Autowired
|
||||
// private DataSource dataSource;
|
||||
|
||||
@Before
|
||||
public void drain() {
|
||||
Message<?> message = replies.receive(100L);
|
||||
@@ -79,6 +82,7 @@ public class RemoteChunkFaultTolerantStepJdbcIntegrationTests {
|
||||
public void testSkipsInWriter() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParametersBuilder().addString("item.three", "fail")
|
||||
.addLong("run.id", 1L).toJobParameters());
|
||||
// System.err.println(new SimpleJdbcTemplate(dataSource).queryForList("SELECT * FROM INT_MESSAGE_GROUP"));
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
|
||||
@@ -86,6 +86,7 @@ public class RetryTransactionalPollingIntegrationTests implements ApplicationCon
|
||||
List<String> expected = Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,fail,fail,d,e"));
|
||||
service.setExpected(expected);
|
||||
waitForResults(bus, expected.size(), 100); // a, b, (fail, fail, [fail]), d, e
|
||||
// System.err.println(service.getProcessed());
|
||||
assertEquals(6, service.getProcessed().size()); // a,b,fail,fail,d,e
|
||||
assertEquals(1, recoverer.getRecovered().size()); // fail
|
||||
assertEquals(expected, service.getProcessed());
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Placeholders batch.*
|
||||
# for Derby:
|
||||
batch.jdbc.driver=org.apache.derby.jdbc.EmbeddedDriver
|
||||
batch.jdbc.url=jdbc:derby:derby-home/test;create=true
|
||||
batch.jdbc.user=app
|
||||
batch.jdbc.password=
|
||||
batch.jdbc.testWhileIdle=false
|
||||
batch.jdbc.validationQuery=
|
||||
batch.data.source.init=true
|
||||
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.DerbyMaxValueIncrementer
|
||||
batch.schema.script=classpath:/org/springframework/batch/core/schema-derby.sql
|
||||
batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-derby.sql
|
||||
integration.schema.script=classpath*:/org/springframework/integration/jdbc/schema-derby.sql
|
||||
integration.drop.script=classpath*:/org/springframework/integration/jdbc/schema-drop-derby.sql
|
||||
@@ -0,0 +1,13 @@
|
||||
# Default database platform is HSQLDB:
|
||||
batch.jdbc.driver=org.h2.Driver
|
||||
batch.jdbc.url=jdbc:h2:file:target/data/h2
|
||||
batch.jdbc.user=sa
|
||||
batch.jdbc.password=
|
||||
batch.jdbc.testWhileIdle=false
|
||||
batch.jdbc.validationQuery=
|
||||
batch.data.source.init=true
|
||||
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.H2SequenceMaxValueIncrementer
|
||||
batch.schema.script=classpath*:/org/springframework/batch/core/schema-h2.sql
|
||||
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-h2.sql
|
||||
integration.schema.script=classpath*:/org/springframework/integration/jdbc/schema-h2.sql
|
||||
integration.drop.script=classpath*:/org/springframework/integration/jdbc/schema-drop-h2.sql
|
||||
@@ -13,3 +13,4 @@ batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.Hs
|
||||
batch.schema.script=classpath*:/org/springframework/batch/core/schema-hsqldb.sql
|
||||
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-hsqldb.sql
|
||||
integration.schema.script=classpath*:/org/springframework/integration/jdbc/schema-hsqldb.sql
|
||||
integration.drop.script=classpath*:/org/springframework/integration/jdbc/schema-drop-hsqldb.sql
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Placeholders batch.*
|
||||
# for MySQL:
|
||||
batch.jdbc.driver=com.mysql.jdbc.Driver
|
||||
batch.jdbc.url=jdbc:mysql://localhost/test
|
||||
batch.jdbc.user=root
|
||||
batch.jdbc.password=root
|
||||
batch.jdbc.testWhileIdle=true
|
||||
batch.jdbc.validationQuery=SELECT 1
|
||||
batch.data.source.init=true
|
||||
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
|
||||
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
|
||||
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-mysql.sql
|
||||
integration.schema.script=classpath*:/org/springframework/integration/jdbc/schema-mysql.sql
|
||||
integration.drop.script=classpath*:/org/springframework/integration/jdbc/schema-drop-mysql.sql
|
||||
@@ -54,17 +54,7 @@
|
||||
<property name="receiveTimeout" value="1000" />
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
|
||||
<property name="scopes">
|
||||
<map>
|
||||
<entry key="thread">
|
||||
<bean class="org.springframework.context.support.SimpleThreadScope" />
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<int-jdbc:message-store id="messageStore" data-source="dataSource"/>
|
||||
<int-jdbc:message-store id="messageStore" data-source="dataSource" />
|
||||
|
||||
<integration:channel id="requests">
|
||||
<integration:queue message-store="messageStore" />
|
||||
@@ -75,7 +65,7 @@
|
||||
<integration:service-activator input-channel="requests" output-channel="replies" ref="chunkHandler">
|
||||
<integration:poller>
|
||||
<integration:interval-trigger interval="100" />
|
||||
<integration:transactional />
|
||||
<integration:transactional isolation="READ_COMMITTED"/>
|
||||
</integration:poller>
|
||||
</integration:service-activator>
|
||||
|
||||
@@ -105,6 +95,7 @@
|
||||
ignore-failures="DROPS">
|
||||
<jdbc:script location="${batch.drop.script}" />
|
||||
<jdbc:script location="${batch.schema.script}" />
|
||||
<jdbc:script location="${integration.drop.script}" />
|
||||
<jdbc:script location="${integration.schema.script}" />
|
||||
</jdbc:initialize-database>
|
||||
|
||||
|
||||
@@ -1,51 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<integration:annotation-config />
|
||||
|
||||
<integration:channel id="requests" />
|
||||
<integration:channel id="replies" />
|
||||
|
||||
<integration:inbound-channel-adapter
|
||||
ref="testCase" method="input" channel="requests">
|
||||
<integration:poller max-messages-per-poll="1">
|
||||
<integration:interval-trigger interval="10" initial-delay="100" />
|
||||
<integration:transactional />
|
||||
</integration:poller>
|
||||
</integration:inbound-channel-adapter>
|
||||
<integration:outbound-channel-adapter
|
||||
ref="testCase" method="output" channel="replies" />
|
||||
|
||||
<bean id="testCase"
|
||||
class="org.springframework.batch.integration.retry.RetryTransactionalPollingIntegrationTests" />
|
||||
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="service" class="org.springframework.batch.integration.retry.SimpleService" />
|
||||
<bean id="recoverer" class="org.springframework.batch.integration.retry.SimpleRecoverer" />
|
||||
<bean id="retryAdvice" class="org.springframework.batch.retry.interceptor.StatefulRetryOperationsInterceptor">
|
||||
<property name="retryOperations">
|
||||
<bean class="org.springframework.batch.retry.support.RetryTemplate">
|
||||
<property name="retryPolicy">
|
||||
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy">
|
||||
<property name="maxAttempts" value="2" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="recoverer" ref="recoverer" />
|
||||
</bean>
|
||||
<aop:config proxy-target-class="true">
|
||||
<aop:advisor advice-ref="retryAdvice" pointcut="execution(* org.springframework.batch.integration.retry.Service+.process(..))" />
|
||||
</aop:config>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.0.xsd
|
||||
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||
|
||||
<integration:annotation-config />
|
||||
|
||||
<integration:channel id="requests" />
|
||||
<integration:channel id="replies" />
|
||||
|
||||
<integration:inbound-channel-adapter ref="testCase" method="input" channel="requests">
|
||||
<integration:poller max-messages-per-poll="1">
|
||||
<integration:interval-trigger interval="10" initial-delay="100" />
|
||||
<integration:transactional />
|
||||
</integration:poller>
|
||||
</integration:inbound-channel-adapter>
|
||||
|
||||
<integration:outbound-channel-adapter ref="testCase" method="output" channel="replies" />
|
||||
|
||||
<bean id="testCase" class="org.springframework.batch.integration.retry.RetryTransactionalPollingIntegrationTests" />
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="service" class="org.springframework.batch.integration.retry.SimpleService" />
|
||||
|
||||
<bean id="recoverer" class="org.springframework.batch.integration.retry.SimpleRecoverer" />
|
||||
|
||||
<bean id="retryAdvice" class="org.springframework.batch.retry.interceptor.StatefulRetryOperationsInterceptor">
|
||||
<property name="retryOperations">
|
||||
<bean class="org.springframework.batch.retry.support.RetryTemplate">
|
||||
<property name="retryPolicy">
|
||||
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy">
|
||||
<property name="maxAttempts" value="2" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="recoverer" ref="recoverer" />
|
||||
</bean>
|
||||
|
||||
<aop:config proxy-target-class="true">
|
||||
<aop:advisor advice-ref="retryAdvice" pointcut="execution(* org.springframework.batch.integration.retry.Service+.process(..))" />
|
||||
</aop:config>
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user