Add Error Handling to RedisStreamMessageProducer
* Use 'onErrorContinue' to continue receiving messages from Stream * Send an `ErrorMessage` to the provided `errorChannel` (if any) * And `@Nullable` to some `MessageProducerSupport` API which definitely may accept `null` * Extract common `buildMessageFromRecord()` method in the `ReactiveRedisStreamMessageProducer`, so all the headers from the stream `Record` are carried to the message independently of the record state - normal send or error sending
This commit is contained in:
committed by
Artem Bilan
parent
5b74db8417
commit
b1a383060d
@@ -34,6 +34,8 @@ import org.springframework.integration.redis.support.RedisHeaders;
|
||||
import org.springframework.integration.support.AbstractIntegrationMessageBuilder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.converter.MessageConversionException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -211,25 +213,38 @@ public class ReactiveRedisStreamMessageProducer extends MessageProducerSupport {
|
||||
}
|
||||
|
||||
Flux<? extends Message<?>> messageFlux =
|
||||
events.map((event) -> {
|
||||
AbstractIntegrationMessageBuilder<?> builder =
|
||||
getMessageBuilderFactory()
|
||||
.withPayload(this.extractPayload ? event.getValue() : event)
|
||||
.setHeader(RedisHeaders.STREAM_KEY, event.getStream())
|
||||
.setHeader(RedisHeaders.STREAM_MESSAGE_ID, event.getId())
|
||||
.setHeader(RedisHeaders.CONSUMER_GROUP, this.consumerGroup)
|
||||
.setHeader(RedisHeaders.CONSUMER, this.consumerName);
|
||||
if (!this.autoAck && this.consumerGroup != null) {
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK,
|
||||
(SimpleAcknowledgment) () ->
|
||||
this.reactiveStreamOperations
|
||||
.acknowledge(this.consumerGroup, event)
|
||||
.subscribe());
|
||||
}
|
||||
return builder.build();
|
||||
});
|
||||
|
||||
events.map((record) -> buildMessageFromRecord(record, this.extractPayload))
|
||||
.onErrorContinue((ex, record) -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
Message<?> failedMessage = buildMessageFromRecord((Record<String, ?>) record, false);
|
||||
MessagingException conversionException =
|
||||
new MessageConversionException(failedMessage,
|
||||
"Cannot deserialize Redis Stream Record", ex);
|
||||
if (!sendErrorMessageIfNecessary(null, conversionException)) {
|
||||
logger.getLog().error(conversionException);
|
||||
}
|
||||
});
|
||||
subscribeToPublisher(messageFlux);
|
||||
}
|
||||
|
||||
private Message<?> buildMessageFromRecord(Record<String, ?> record, boolean extractPayload) {
|
||||
AbstractIntegrationMessageBuilder<?> builder =
|
||||
getMessageBuilderFactory()
|
||||
.withPayload(extractPayload ? record.getValue() : record)
|
||||
.setHeader(RedisHeaders.STREAM_KEY, record.getStream())
|
||||
.setHeader(RedisHeaders.STREAM_MESSAGE_ID, record.getId())
|
||||
.setHeader(RedisHeaders.CONSUMER_GROUP, this.consumerGroup)
|
||||
.setHeader(RedisHeaders.CONSUMER, this.consumerName);
|
||||
|
||||
if (!this.autoAck && this.consumerGroup != null) {
|
||||
builder.setHeader(IntegrationMessageHeaderAccessor.ACKNOWLEDGMENT_CALLBACK,
|
||||
(SimpleAcknowledgment) () ->
|
||||
this.reactiveStreamOperations
|
||||
.acknowledge(this.consumerGroup, record)
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user