GH-3797: Improve batch processing in the framework (#3820)

* GH-3797: Improve batch processing in the framework

Fixes https://github.com/spring-projects/spring-integration/issues/3797

* Handle `Message` items of the `Iterable` payload properly in the `JdbcMessageHandler`.
Otherwise, they've been wrapped into an extra `Message`
* Produce a single message with a `Collection<Message<?>>` payload in the `AggregatingMessageHandler`
when the `getOutputProcessor()` is not an instance of `SimpleMessageGroupProcessor`
* Mention these changes in docs
* Point to the error handling sample from docs

* * Fix language in docs

Co-authored-by: Gary Russell <grussell@vmware.com>

Co-authored-by: Gary Russell <grussell@vmware.com>
This commit is contained in:
Artem Bilan
2022-06-07 10:14:53 -04:00
committed by GitHub
parent 4f49038e17
commit e855f13d8e
8 changed files with 100 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,6 +72,21 @@ public class AggregatingMessageHandler extends AbstractCorrelatingMessageHandler
return this.expireGroupsUponCompletion;
}
/**
* Check an {@link Iterable} result for split possibility on the output production:
* the items of the collection have to be instances of {@link Message}
* or {@link org.springframework.integration.support.AbstractIntegrationMessageBuilder}
* and {@link #getOutputProcessor()} has to be a {@link SimpleMessageGroupProcessor}.
* Otherwise, a single reply message is emitted with the whole {@link Iterable} as its payload.
* @param reply the {@link Iterable} result to check for split possibility.
* @return true if the {@link Iterable} result has to be split into individual messages.
* @since 6.0
*/
@Override
protected boolean shouldSplitOutput(Iterable<?> reply) {
return getOutputProcessor() instanceof SimpleMessageGroupProcessor && super.shouldSplitOutput(reply);
}
/**
* Complete the group and remove all its messages.
* If the {@link #expireGroupsUponCompletion} is true, then remove group fully.

View File

@@ -44,7 +44,6 @@ import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.aggregator.AggregatingMessageHandler;
import org.springframework.integration.aggregator.ExpressionEvaluatingCorrelationStrategy;
import org.springframework.integration.aggregator.ExpressionEvaluatingReleaseStrategy;
import org.springframework.integration.aggregator.SimpleMessageGroupProcessor;
import org.springframework.integration.annotation.BridgeFrom;
import org.springframework.integration.annotation.BridgeTo;
import org.springframework.integration.annotation.Filter;
@@ -69,6 +68,7 @@ import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.filter.ExpressionEvaluatingSelector;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.splitter.DefaultMessageSplitter;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.transformer.ExpressionEvaluatingTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
@@ -178,12 +178,11 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
MessageHistory messageHistory = MessageHistory.read(message);
assertThat(messageHistory).isNotNull();
String messageHistoryString = messageHistory.toString();
assertThat(messageHistoryString).contains("routerChannel")
.contains("filterChannel")
.contains("aggregatorChannel")
.contains("splitterChannel")
.contains("serviceChannel")
.doesNotContain("discardChannel");
assertThat(messageHistoryString)
.contains("routerChannel", "filterChannel", "aggregatorChannel", "serviceChannel")
.doesNotContain("discardChannel")
// history header is not overridden in splitter for individual message from message group emitted before
.doesNotContain("splitterChannel");
}
assertThat(this.skippedServiceActivator).isNull();
@@ -248,10 +247,10 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
this.reactiveMessageHandlerChannel.send(new GenericMessage<>("test"));
StepVerifier.create(
this.contextConfiguration.messageMono
.asMono()
.map(Message::getPayload)
.cast(String.class))
this.contextConfiguration.messageMono
.asMono()
.map(Message::getPayload)
.cast(String.class))
.expectNext("test")
.verifyComplete();
}
@@ -332,7 +331,7 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
@Bean
@ServiceActivator(inputChannel = "aggregatorChannel")
public MessageHandler aggregator() {
AggregatingMessageHandler handler = new AggregatingMessageHandler(new SimpleMessageGroupProcessor());
AggregatingMessageHandler handler = new AggregatingMessageHandler(MessageGroup::getMessages);
handler.setCorrelationStrategy(new ExpressionEvaluatingCorrelationStrategy("1"));
handler.setReleaseStrategy(new ExpressionEvaluatingReleaseStrategy("size() == 10"));
handler.setOutputChannelName("splitterChannel");
@@ -346,7 +345,7 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
@Bean
public CountDownLatch reactiveCustomizerLatch() {
return new CountDownLatch(10);
return new CountDownLatch(1);
}
@Bean