Search in sources :

Example 1 with OffsetSpecification

use of com.rabbitmq.stream.OffsetSpecification in project rabbitmq-stream-java-client by rabbitmq.

the class StreamConsumerTest method useSubscriptionListenerToRestartExactlyWhereDesired.

@Test
@DisabledIfRabbitMqCtlNotSet
void useSubscriptionListenerToRestartExactlyWhereDesired() throws Exception {
    AtomicInteger subscriptionListenerCallCount = new AtomicInteger(0);
    AtomicInteger receivedMessages = new AtomicInteger(0);
    AtomicLong offsetTracking = new AtomicLong(0);
    AtomicBoolean started = new AtomicBoolean(false);
    int storeEvery = 10_000;
    String reference = "ref-1";
    CountDownLatch poisonLatch = new CountDownLatch(1);
    environment.consumerBuilder().name(reference).stream(stream).offset(OffsetSpecification.first()).subscriptionListener(subscriptionContext -> {
        subscriptionListenerCallCount.getAndIncrement();
        OffsetSpecification offsetSpecification = started.get() ? OffsetSpecification.offset(offsetTracking.get() + 1) : subscriptionContext.offsetSpecification();
        subscriptionContext.offsetSpecification(offsetSpecification);
    }).messageHandler((context, message) -> {
        receivedMessages.incrementAndGet();
        offsetTracking.set(context.offset());
        started.set(true);
        if ("poison".equals(new String(message.getBodyAsBinary()))) {
            poisonLatch.countDown();
        }
    }).autoTrackingStrategy().flushInterval(// long flush interval
    Duration.ofMinutes(60)).messageCountBeforeStorage(storeEvery).builder().build();
    AtomicInteger publishedMessages = new AtomicInteger(0);
    Producer producer = environment.producerBuilder().stream(stream).build();
    IntConsumer publish = messagesToPublish -> {
        publishedMessages.addAndGet(messagesToPublish);
        IntStream.range(0, messagesToPublish).forEach(i -> producer.send(producer.messageBuilder().addData("".getBytes()).build(), confirmationStatus -> {
        }));
    };
    publish.accept(storeEvery * 2 - 100);
    waitAtMost(5, () -> receivedMessages.get() == publishedMessages.get());
    Host.killConnection("rabbitmq-stream-consumer-0");
    publish.accept(storeEvery * 2);
    producer.send(producer.messageBuilder().addData("poison".getBytes()).build(), confirmationStatus -> {
    });
    latchAssert(poisonLatch).completes();
    // no duplicates because the custom offset tracking overrides the stored offset in the
    // subscription listener
    assertThat(receivedMessages).hasValue(publishedMessages.get() + 1);
}
Also used : IntStream(java.util.stream.IntStream) BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) StreamDoesNotExistException(com.rabbitmq.stream.StreamDoesNotExistException) IntConsumer(java.util.function.IntConsumer) TestUtils.latchAssert(com.rabbitmq.stream.impl.TestUtils.latchAssert) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) UnaryOperator(java.util.function.UnaryOperator) AtomicReference(java.util.concurrent.atomic.AtomicReference) TestUtils.b(com.rabbitmq.stream.impl.TestUtils.b) TestUtils.streamName(com.rabbitmq.stream.impl.TestUtils.streamName) ConfirmationHandler(com.rabbitmq.stream.ConfirmationHandler) DisabledIfRabbitMqCtlNotSet(com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet) Assertions.assertThatThrownBy(org.assertj.core.api.Assertions.assertThatThrownBy) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConsumerBuilder(com.rabbitmq.stream.ConsumerBuilder) Duration(java.time.Duration) MethodSource(org.junit.jupiter.params.provider.MethodSource) Host(com.rabbitmq.stream.Host) TestUtils.waitAtMost(com.rabbitmq.stream.impl.TestUtils.waitAtMost) EventLoopGroup(io.netty.channel.EventLoopGroup) Environment(com.rabbitmq.stream.Environment) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) UUID(java.util.UUID) Consumer(com.rabbitmq.stream.Consumer) Producer(com.rabbitmq.stream.Producer) String.format(java.lang.String.format) EnvironmentBuilder(com.rabbitmq.stream.EnvironmentBuilder) ConsumerInfo(com.rabbitmq.stream.impl.MonitoringTestUtils.ConsumerInfo) TestInfo(org.junit.jupiter.api.TestInfo) BackOffDelayPolicy(com.rabbitmq.stream.BackOffDelayPolicy) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) AfterEach(org.junit.jupiter.api.AfterEach) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Stream(java.util.stream.Stream) Collections(java.util.Collections) OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) TestUtils.localhost(com.rabbitmq.stream.impl.TestUtils.localhost) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) Producer(com.rabbitmq.stream.Producer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CountDownLatch(java.util.concurrent.CountDownLatch) IntConsumer(java.util.function.IntConsumer) DisabledIfRabbitMqCtlNotSet(com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 2 with OffsetSpecification

use of com.rabbitmq.stream.OffsetSpecification in project rabbitmq-stream-java-client by rabbitmq.

the class StreamConsumerTest method externalOffsetTrackingWithSubscriptionListener.

@Test
@DisabledIfRabbitMqCtlNotSet
void externalOffsetTrackingWithSubscriptionListener() throws Exception {
    AtomicInteger subscriptionListenerCallCount = new AtomicInteger(0);
    AtomicInteger receivedMessages = new AtomicInteger(0);
    AtomicLong offsetTracking = new AtomicLong(0);
    AtomicBoolean started = new AtomicBoolean(false);
    environment.consumerBuilder().stream(stream).offset(OffsetSpecification.first()).subscriptionListener(subscriptionContext -> {
        subscriptionListenerCallCount.incrementAndGet();
        OffsetSpecification offsetSpecification = started.get() ? OffsetSpecification.offset(offsetTracking.get() + 1) : subscriptionContext.offsetSpecification();
        subscriptionContext.offsetSpecification(offsetSpecification);
    }).messageHandler((context, message) -> {
        receivedMessages.incrementAndGet();
        offsetTracking.set(context.offset());
        started.set(true);
    }).build();
    int messageCount = 10_000;
    Producer producer = environment.producerBuilder().stream(stream).build();
    Runnable publish = () -> IntStream.range(0, messageCount).forEach(i -> producer.send(producer.messageBuilder().addData("".getBytes()).build(), confirmationStatus -> {
    }));
    publish.run();
    waitAtMost(5, () -> receivedMessages.get() == messageCount);
    assertThat(offsetTracking.get()).isGreaterThanOrEqualTo(messageCount - 1);
    Host.killConnection("rabbitmq-stream-consumer-0");
    waitAtMost(recoveryInitialDelay.multipliedBy(2), () -> subscriptionListenerCallCount.get() == 2);
    publish.run();
    waitAtMost(5, () -> receivedMessages.get() == messageCount * 2);
    assertThat(offsetTracking.get()).isGreaterThanOrEqualTo(messageCount * 2 - 1);
}
Also used : IntStream(java.util.stream.IntStream) BeforeEach(org.junit.jupiter.api.BeforeEach) Arrays(java.util.Arrays) Assertions.assertThat(org.assertj.core.api.Assertions.assertThat) StreamDoesNotExistException(com.rabbitmq.stream.StreamDoesNotExistException) IntConsumer(java.util.function.IntConsumer) TestUtils.latchAssert(com.rabbitmq.stream.impl.TestUtils.latchAssert) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) UnaryOperator(java.util.function.UnaryOperator) AtomicReference(java.util.concurrent.atomic.AtomicReference) TestUtils.b(com.rabbitmq.stream.impl.TestUtils.b) TestUtils.streamName(com.rabbitmq.stream.impl.TestUtils.streamName) ConfirmationHandler(com.rabbitmq.stream.ConfirmationHandler) DisabledIfRabbitMqCtlNotSet(com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet) Assertions.assertThatThrownBy(org.assertj.core.api.Assertions.assertThatThrownBy) ExtendWith(org.junit.jupiter.api.extension.ExtendWith) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ConsumerBuilder(com.rabbitmq.stream.ConsumerBuilder) Duration(java.time.Duration) MethodSource(org.junit.jupiter.params.provider.MethodSource) Host(com.rabbitmq.stream.Host) TestUtils.waitAtMost(com.rabbitmq.stream.impl.TestUtils.waitAtMost) EventLoopGroup(io.netty.channel.EventLoopGroup) Environment(com.rabbitmq.stream.Environment) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) UUID(java.util.UUID) Consumer(com.rabbitmq.stream.Consumer) Producer(com.rabbitmq.stream.Producer) String.format(java.lang.String.format) EnvironmentBuilder(com.rabbitmq.stream.EnvironmentBuilder) ConsumerInfo(com.rabbitmq.stream.impl.MonitoringTestUtils.ConsumerInfo) TestInfo(org.junit.jupiter.api.TestInfo) BackOffDelayPolicy(com.rabbitmq.stream.BackOffDelayPolicy) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) CountDownLatch(java.util.concurrent.CountDownLatch) AtomicLong(java.util.concurrent.atomic.AtomicLong) List(java.util.List) AfterEach(org.junit.jupiter.api.AfterEach) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) Stream(java.util.stream.Stream) Collections(java.util.Collections) OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) TestUtils.localhost(com.rabbitmq.stream.impl.TestUtils.localhost) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicLong(java.util.concurrent.atomic.AtomicLong) OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) Producer(com.rabbitmq.stream.Producer) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) DisabledIfRabbitMqCtlNotSet(com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet) Test(org.junit.jupiter.api.Test) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest)

Example 3 with OffsetSpecification

use of com.rabbitmq.stream.OffsetSpecification in project rabbitmq-stream-java-client by rabbitmq.

the class ConsumersCoordinatorTest method shouldRestartWhereItLeftOffAfterDisruption.

@ParameterizedTest
@MethodSource("disruptionArguments")
void shouldRestartWhereItLeftOffAfterDisruption(Consumer<ConsumersCoordinatorTest> configurator) throws Exception {
    scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    when(environment.scheduledExecutorService()).thenReturn(scheduledExecutorService);
    Duration retryDelay = Duration.ofMillis(100);
    when(environment.recoveryBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(environment.topologyUpdateBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(consumer.isOpen()).thenReturn(true);
    when(locator.metadata("stream")).thenReturn(metadata(null, replicas())).thenReturn(metadata(null, Collections.emptyList())).thenReturn(metadata(null, replicas()));
    ArgumentCaptor<OffsetSpecification> offsetSpecificationArgumentCaptor = ArgumentCaptor.forClass(OffsetSpecification.class);
    when(clientFactory.client(any())).thenReturn(client);
    when(client.subscribe(subscriptionIdCaptor.capture(), anyString(), offsetSpecificationArgumentCaptor.capture(), anyInt(), anyMap())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    Runnable closingRunnable = coordinator.subscribe(consumer, "stream", OffsetSpecification.first(), null, NO_OP_SUBSCRIPTION_LISTENER, (offset, message) -> {
    });
    verify(clientFactory, times(1)).client(any());
    verify(client, times(1)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(0).isEqualTo(OffsetSpecification.first());
    long lastReceivedOffset = 10;
    messageListener.handle(subscriptionIdCaptor.getValue(), lastReceivedOffset, 0, new WrapperMessageBuilder().build());
    configurator.accept(this);
    Thread.sleep(retryDelay.toMillis() * 5);
    verify(client, times(2)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(1).isEqualTo(OffsetSpecification.offset(lastReceivedOffset));
    when(client.unsubscribe(subscriptionIdCaptor.getValue())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    closingRunnable.run();
    verify(client, times(1)).unsubscribe(subscriptionIdCaptor.getValue());
}
Also used : OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) WrapperMessageBuilder(com.rabbitmq.stream.codec.WrapperMessageBuilder) Duration(java.time.Duration) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 4 with OffsetSpecification

use of com.rabbitmq.stream.OffsetSpecification in project rabbitmq-stream-java-client by rabbitmq.

the class ConsumersCoordinatorTest method shouldUseStoredOffsetOnRecovery.

@ParameterizedTest
@MethodSource("disruptionArguments")
@SuppressWarnings("unchecked")
void shouldUseStoredOffsetOnRecovery(Consumer<ConsumersCoordinatorTest> configurator) throws Exception {
    scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    when(environment.scheduledExecutorService()).thenReturn(scheduledExecutorService);
    Duration retryDelay = Duration.ofMillis(100);
    when(environment.recoveryBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(environment.topologyUpdateBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(consumer.isOpen()).thenReturn(true);
    when(locator.metadata("stream")).thenReturn(metadata(null, replicas())).thenReturn(metadata(null, Collections.emptyList())).thenReturn(metadata(null, replicas()));
    when(clientFactory.client(any())).thenReturn(client);
    String consumerName = "consumer-name";
    long lastStoredOffset = 5;
    long lastReceivedOffset = 10;
    when(client.queryOffset(consumerName, "stream")).thenReturn(new QueryOffsetResponse(Constants.RESPONSE_CODE_OK, 0L)).thenReturn(new QueryOffsetResponse(Constants.RESPONSE_CODE_OK, lastStoredOffset));
    ArgumentCaptor<OffsetSpecification> offsetSpecificationArgumentCaptor = ArgumentCaptor.forClass(OffsetSpecification.class);
    ArgumentCaptor<Map<String, String>> subscriptionPropertiesArgumentCaptor = ArgumentCaptor.forClass(Map.class);
    when(client.subscribe(subscriptionIdCaptor.capture(), anyString(), offsetSpecificationArgumentCaptor.capture(), anyInt(), subscriptionPropertiesArgumentCaptor.capture())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    Runnable closingRunnable = coordinator.subscribe(consumer, "stream", null, consumerName, NO_OP_SUBSCRIPTION_LISTENER, (offset, message) -> {
    });
    verify(clientFactory, times(1)).client(any());
    verify(client, times(1)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(0).isEqualTo(OffsetSpecification.next());
    assertThat(subscriptionPropertiesArgumentCaptor.getAllValues()).element(0).isEqualTo(Collections.singletonMap("name", "consumer-name"));
    messageListener.handle(subscriptionIdCaptor.getValue(), lastReceivedOffset, 0, new WrapperMessageBuilder().build());
    configurator.accept(this);
    Thread.sleep(retryDelay.toMillis() * 5);
    verify(client, times(2)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(1).isEqualTo(OffsetSpecification.offset(lastStoredOffset + 1)).isNotEqualTo(OffsetSpecification.offset(lastReceivedOffset));
    assertThat(subscriptionPropertiesArgumentCaptor.getAllValues()).element(1).isEqualTo(Collections.singletonMap("name", "consumer-name"));
    when(client.unsubscribe(subscriptionIdCaptor.getValue())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    closingRunnable.run();
    verify(client, times(1)).unsubscribe(subscriptionIdCaptor.getValue());
}
Also used : OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) WrapperMessageBuilder(com.rabbitmq.stream.codec.WrapperMessageBuilder) QueryOffsetResponse(com.rabbitmq.stream.impl.Client.QueryOffsetResponse) Duration(java.time.Duration) ArgumentMatchers.anyString(org.mockito.ArgumentMatchers.anyString) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ArgumentMatchers.anyMap(org.mockito.ArgumentMatchers.anyMap) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Example 5 with OffsetSpecification

use of com.rabbitmq.stream.OffsetSpecification in project rabbitmq-stream-java-client by rabbitmq.

the class ConsumersCoordinatorTest method shouldReUseInitialOffsetSpecificationAfterDisruptionIfNoMessagesReceived.

@ParameterizedTest
@MethodSource("disruptionArguments")
void shouldReUseInitialOffsetSpecificationAfterDisruptionIfNoMessagesReceived(Consumer<ConsumersCoordinatorTest> configurator) throws Exception {
    scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    when(environment.scheduledExecutorService()).thenReturn(scheduledExecutorService);
    Duration retryDelay = Duration.ofMillis(100);
    when(environment.recoveryBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(environment.topologyUpdateBackOffDelayPolicy()).thenReturn(BackOffDelayPolicy.fixed(retryDelay));
    when(consumer.isOpen()).thenReturn(true);
    when(locator.metadata("stream")).thenReturn(metadata(null, replicas())).thenReturn(metadata(null, Collections.emptyList())).thenReturn(metadata(null, replicas()));
    ArgumentCaptor<OffsetSpecification> offsetSpecificationArgumentCaptor = ArgumentCaptor.forClass(OffsetSpecification.class);
    when(clientFactory.client(any())).thenReturn(client);
    when(client.subscribe(subscriptionIdCaptor.capture(), anyString(), offsetSpecificationArgumentCaptor.capture(), anyInt(), anyMap())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    Runnable closingRunnable = coordinator.subscribe(consumer, "stream", OffsetSpecification.next(), null, NO_OP_SUBSCRIPTION_LISTENER, (offset, message) -> {
    });
    verify(clientFactory, times(1)).client(any());
    verify(client, times(1)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(0).isEqualTo(OffsetSpecification.next());
    configurator.accept(this);
    Thread.sleep(retryDelay.toMillis() * 5);
    verify(client, times(2)).subscribe(anyByte(), anyString(), any(OffsetSpecification.class), anyInt(), anyMap());
    assertThat(offsetSpecificationArgumentCaptor.getAllValues()).element(1).isEqualTo(OffsetSpecification.next());
    when(client.unsubscribe(subscriptionIdCaptor.getValue())).thenReturn(new Client.Response(Constants.RESPONSE_CODE_OK));
    closingRunnable.run();
    verify(client, times(1)).unsubscribe(subscriptionIdCaptor.getValue());
}
Also used : OffsetSpecification(com.rabbitmq.stream.OffsetSpecification) Duration(java.time.Duration) ParameterizedTest(org.junit.jupiter.params.ParameterizedTest) MethodSource(org.junit.jupiter.params.provider.MethodSource)

Aggregations

OffsetSpecification (com.rabbitmq.stream.OffsetSpecification)5 Duration (java.time.Duration)5 ParameterizedTest (org.junit.jupiter.params.ParameterizedTest)5 MethodSource (org.junit.jupiter.params.provider.MethodSource)5 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)3 BackOffDelayPolicy (com.rabbitmq.stream.BackOffDelayPolicy)2 ConfirmationHandler (com.rabbitmq.stream.ConfirmationHandler)2 Consumer (com.rabbitmq.stream.Consumer)2 ConsumerBuilder (com.rabbitmq.stream.ConsumerBuilder)2 Environment (com.rabbitmq.stream.Environment)2 EnvironmentBuilder (com.rabbitmq.stream.EnvironmentBuilder)2 Host (com.rabbitmq.stream.Host)2 Producer (com.rabbitmq.stream.Producer)2 StreamDoesNotExistException (com.rabbitmq.stream.StreamDoesNotExistException)2 WrapperMessageBuilder (com.rabbitmq.stream.codec.WrapperMessageBuilder)2 ConsumerInfo (com.rabbitmq.stream.impl.MonitoringTestUtils.ConsumerInfo)2 DisabledIfRabbitMqCtlNotSet (com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet)2 TestUtils.b (com.rabbitmq.stream.impl.TestUtils.b)2 TestUtils.latchAssert (com.rabbitmq.stream.impl.TestUtils.latchAssert)2 TestUtils.localhost (com.rabbitmq.stream.impl.TestUtils.localhost)2