use of com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet 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);
}
use of com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet 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);
}
use of com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet in project rabbitmq-stream-java-client by rabbitmq.
the class StreamConsumerTest method duplicatesWhenResubscribeAfterDisconnectionWithLongFlushInterval.
@Test
@DisabledIfRabbitMqCtlNotSet
void duplicatesWhenResubscribeAfterDisconnectionWithLongFlushInterval() throws Exception {
AtomicInteger receivedMessages = new AtomicInteger(0);
int storeEvery = 10_000;
String reference = "ref-1";
AtomicBoolean receivedPoison = new AtomicBoolean(false);
environment.consumerBuilder().name(reference).stream(stream).offset(OffsetSpecification.first()).messageHandler((context, message) -> {
receivedMessages.incrementAndGet();
if ("poison".equals(new String(message.getBodyAsBinary()))) {
receivedPoison.set(true);
}
}).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);
waitAtMost(() -> {
producer.send(producer.messageBuilder().addData("poison".getBytes()).build(), confirmationStatus -> {
});
publishedMessages.incrementAndGet();
return receivedPoison.get();
});
// we have duplicates because the last stored value is behind and the re-subscription uses it
assertThat(receivedMessages).hasValueGreaterThan(publishedMessages.get());
}
use of com.rabbitmq.stream.impl.TestUtils.DisabledIfRabbitMqCtlNotSet in project rabbitmq-stream-java-client by rabbitmq.
the class StreamConsumerTest method consumerShouldReUseInitialOffsetSpecificationAfterDisruptionIfNoMessagesReceived.
@Test
@DisabledIfRabbitMqCtlNotSet
void consumerShouldReUseInitialOffsetSpecificationAfterDisruptionIfNoMessagesReceived() throws Exception {
int messageCountFirstWave = 10_000;
Producer producer = environment.producerBuilder().stream(stream).build();
// send a first wave of messages, they should be consumed later
CountDownLatch publishLatch = new CountDownLatch(messageCountFirstWave);
IntStream.range(0, messageCountFirstWave).forEach(i -> producer.send(producer.messageBuilder().addData("first wave".getBytes()).build(), confirmationStatus -> publishLatch.countDown()));
latchAssert(publishLatch).completes();
// setting up the consumer, offset spec "next", it should only consume messages of the second
// wave
AtomicInteger consumedCount = new AtomicInteger(0);
CountDownLatch consumeLatch = new CountDownLatch(1);
Set<String> bodies = ConcurrentHashMap.newKeySet(10);
environment.consumerBuilder().stream(stream).offset(OffsetSpecification.next()).messageHandler((context, message) -> {
String body = new String(message.getBodyAsBinary());
bodies.add(body);
if (body.contains("second wave")) {
consumeLatch.countDown();
}
}).build();
// killing the consumer connection to trigger an internal restart
Host.killConnection("rabbitmq-stream-consumer-0");
// no messages should have been received
assertThat(consumedCount.get()).isZero();
// starting the second wave, it sends a message every 100 ms
AtomicBoolean keepPublishing = new AtomicBoolean(true);
new Thread(() -> {
while (keepPublishing.get()) {
producer.send(producer.messageBuilder().addData("second wave".getBytes()).build(), confirmationStatus -> publishLatch.countDown());
waitMs(100);
}
}).start();
// the consumer should restart consuming with its initial offset spec, "next"
try {
latchAssert(consumeLatch).completes(recoveryInitialDelay.multipliedBy(2));
assertThat(bodies).hasSize(1).contains("second wave");
} finally {
keepPublishing.set(false);
}
}
Aggregations