Add ReactiveRedisOperations.listenToLater(…) to await subscriptions.
Original Pull Request: #2052
This commit is contained in:
committed by
Christoph Strobl
parent
fe51d78537
commit
9480851a2e
@@ -116,6 +116,49 @@ public interface ReactiveRedisOperations<K, V> {
|
||||
*/
|
||||
Flux<? extends Message<String, V>> listenTo(Topic... topics);
|
||||
|
||||
/**
|
||||
* Subscribe to the given Redis {@code channels} and emit {@link Message messages} received for those. The
|
||||
* {@link Mono} completes once the {@link Topic topic} subscriptions are registered.
|
||||
*
|
||||
* @param channels must not be {@literal null}.
|
||||
* @return a hot sequence of {@link Message messages}.
|
||||
* @since 2.6
|
||||
* @see org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer#receiveLater(ChannelTopic...)
|
||||
*/
|
||||
default Mono<Flux<? extends Message<String, V>>> listenToChannelLater(String... channels) {
|
||||
|
||||
Assert.notNull(channels, "Channels must not be null!");
|
||||
|
||||
return listenToLater(Arrays.stream(channels).map(ChannelTopic::of).toArray(ChannelTopic[]::new));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the Redis channels matching the given {@code pattern} and emit {@link Message messages} received for
|
||||
* those. The {@link Mono} completes once the {@link Topic topic} subscriptions are registered.
|
||||
*
|
||||
* @param patterns must not be {@literal null}.
|
||||
* @return a hot sequence of {@link Message messages}.
|
||||
* @since 2.6
|
||||
* @see org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer#receiveLater(PatternTopic...)
|
||||
*/
|
||||
default Mono<Flux<? extends Message<String, V>>> listenToPatternLater(String... patterns) {
|
||||
|
||||
Assert.notNull(patterns, "Patterns must not be null!");
|
||||
return listenToLater(Arrays.stream(patterns).map(PatternTopic::of).toArray(PatternTopic[]::new));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to the Redis channels for the given {@link Topic topics} and emit {@link Message messages} received for
|
||||
* those. The {@link Mono} completes once the {@link Topic topic} subscriptions are registered.
|
||||
*
|
||||
* @param topics must not be {@literal null}.
|
||||
* @return a hot sequence of {@link Message messages}.
|
||||
* @since 2.6
|
||||
* @see org.springframework.data.redis.listener.ReactiveRedisMessageListenerContainer#receiveLater(Iterable,
|
||||
* RedisSerializationContext.SerializationPair, RedisSerializationContext.SerializationPair)
|
||||
*/
|
||||
Mono<Flux<? extends Message<String, V>>> listenToLater(Topic... topics);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with Redis Keys
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -237,6 +237,21 @@ public class ReactiveRedisTemplate<K, V> implements ReactiveRedisOperations<K, V
|
||||
.doFinally((signalType) -> container.destroyLater().subscribe());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.core.ReactiveRedisOperations#listenToLater(org.springframework.data.redis.listener.Topic[])
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Mono<Flux<? extends Message<String, V>>> listenToLater(Topic... topics) {
|
||||
|
||||
ReactiveRedisMessageListenerContainer container = new ReactiveRedisMessageListenerContainer(getConnectionFactory());
|
||||
|
||||
return (Mono) container.receiveLater(Arrays.asList(topics), getSerializationContext().getStringSerializationPair(),
|
||||
getSerializationContext().getValueSerializationPair()) //
|
||||
.doFinally((signalType) -> container.destroyLater().subscribe());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Methods dealing with Redis keys
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -343,7 +343,7 @@ public class ReactiveRedisMessageListenerContainer implements DisposableBean {
|
||||
* @throws InvalidDataAccessApiUsageException if {@code topics} is empty.
|
||||
* @since 2.6
|
||||
*/
|
||||
private <C, B> Mono<Flux<Message<C, B>>> receiveLater(Iterable<? extends Topic> topics,
|
||||
public <C, B> Mono<Flux<Message<C, B>>> receiveLater(Iterable<? extends Topic> topics,
|
||||
SerializationPair<C> channelSerializer, SerializationPair<B> messageSerializer) {
|
||||
|
||||
Assert.notNull(topics, "Topics must not be null!");
|
||||
|
||||
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assumptions.*;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import java.time.Duration;
|
||||
@@ -27,6 +28,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
@@ -441,7 +443,29 @@ public class ReactiveRedisTemplateIntegrationTests<K, V> {
|
||||
|
||||
redisTemplate.listenToChannel(channel).as(StepVerifier::create) //
|
||||
.thenAwait(Duration.ofMillis(500)) // just make sure we the subscription completed
|
||||
.then(() -> redisTemplate.convertAndSend(channel, message).block()) //
|
||||
.then(() -> redisTemplate.convertAndSend(channel, message).subscribe()) //
|
||||
.assertNext(received -> {
|
||||
|
||||
assertThat(received).isInstanceOf(ChannelMessage.class);
|
||||
assertThat(received.getMessage()).isEqualTo(message);
|
||||
assertThat(received.getChannel()).isEqualTo(channel);
|
||||
}) //
|
||||
.thenAwait(Duration.ofMillis(10)) //
|
||||
.thenCancel() //
|
||||
.verify(Duration.ofSeconds(3));
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // GH-1622
|
||||
@EnabledIfLongRunningTest
|
||||
void listenToLaterChannelShouldReceiveChannelMessagesCorrectly() {
|
||||
|
||||
String channel = "my-channel";
|
||||
|
||||
V message = valueFactory.instance();
|
||||
|
||||
redisTemplate.listenToChannelLater(channel) //
|
||||
.doOnNext(it -> redisTemplate.convertAndSend(channel, message).subscribe()).flatMapMany(Function.identity()) //
|
||||
.as(StepVerifier::create) //
|
||||
.assertNext(received -> {
|
||||
|
||||
assertThat(received).isInstanceOf(ChannelMessage.class);
|
||||
@@ -455,7 +479,7 @@ public class ReactiveRedisTemplateIntegrationTests<K, V> {
|
||||
|
||||
@ParameterizedRedisTest // DATAREDIS-612
|
||||
@EnabledIfLongRunningTest
|
||||
void listenToChannelPatternShouldReceiveChannelMessagesCorrectly() throws InterruptedException {
|
||||
void listenToPatternShouldReceiveChannelMessagesCorrectly() {
|
||||
|
||||
String channel = "my-channel";
|
||||
String pattern = "my-*";
|
||||
@@ -466,7 +490,32 @@ public class ReactiveRedisTemplateIntegrationTests<K, V> {
|
||||
|
||||
stream.as(StepVerifier::create) //
|
||||
.thenAwait(Duration.ofMillis(500)) // just make sure we the subscription completed
|
||||
.then(() -> redisTemplate.convertAndSend(channel, message).block()) //
|
||||
.then(() -> redisTemplate.convertAndSend(channel, message).subscribe()) //
|
||||
.assertNext(received -> {
|
||||
|
||||
assertThat(received).isInstanceOf(PatternMessage.class);
|
||||
assertThat(received.getMessage()).isEqualTo(message);
|
||||
assertThat(received.getChannel()).isEqualTo(channel);
|
||||
assertThat(((PatternMessage) received).getPattern()).isEqualTo(pattern);
|
||||
}) //
|
||||
.thenCancel() //
|
||||
.verify(Duration.ofSeconds(3));
|
||||
}
|
||||
|
||||
@ParameterizedRedisTest // GH-1622
|
||||
@EnabledIfLongRunningTest
|
||||
void listenToPatternLaterShouldReceiveChannelMessagesCorrectly() {
|
||||
|
||||
String channel = "my-channel";
|
||||
String pattern = "my-*";
|
||||
|
||||
V message = valueFactory.instance();
|
||||
|
||||
Mono<Flux<? extends Message<String, V>>> stream = redisTemplate.listenToPatternLater(pattern);
|
||||
|
||||
stream.doOnNext(it -> redisTemplate.convertAndSend(channel, message).subscribe()) //
|
||||
.flatMapMany(Function.identity()) //
|
||||
.as(StepVerifier::create) //
|
||||
.assertNext(received -> {
|
||||
|
||||
assertThat(received).isInstanceOf(PatternMessage.class);
|
||||
|
||||
Reference in New Issue
Block a user