GH-125: Introduce sync mode for KafkaProducerMH
Fixes: GH-125 (https://github.com/spring-projects/spring-integration-kafka/issues/125) * Add `sync` mode for the `KafkaProducerMessageHandler` (`false` by default) to wait for result from the send `Future` * Add `sendTimeout` do not block `Future.get()` forever * Provide test-case based on the `MockProducer` to complete the record with an exception and verify that the `sync` mode works well * Some dependencies upgrade Wrap `Future.get()` `TimeoutException` into `MessageTimeoutException` Fix whitespace after comma
This commit is contained in:
@@ -17,14 +17,29 @@
|
||||
package org.springframework.integration.kafka.config.xml;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.apache.kafka.clients.producer.MockProducer;
|
||||
import org.apache.kafka.common.serialization.IntegerSerializer;
|
||||
import org.apache.kafka.common.serialization.StringSerializer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.MessageTimeoutException;
|
||||
import org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.kafka.core.KafkaTemplate;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@@ -54,4 +69,40 @@ public class KafkaOutboundAdapterParserTests {
|
||||
assertThat(TestUtils.getPropertyValue(messageHandler, "partitionIdExpression.expression")).isEqualTo("2");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSyncMode() {
|
||||
MockProducer<Integer, String> mockProducer =
|
||||
new MockProducer<>(false, new IntegerSerializer(), new StringSerializer());
|
||||
KafkaTemplate<Integer, String> template = new KafkaTemplate<>(() -> mockProducer);
|
||||
KafkaProducerMessageHandler<Integer, String> handler = new KafkaProducerMessageHandler<>(template);
|
||||
handler.setBeanFactory(mock(BeanFactory.class));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
handler.setSync(true);
|
||||
handler.setTopicExpression(new LiteralExpression("foo"));
|
||||
|
||||
Executors.newSingleThreadExecutor()
|
||||
.submit(() -> {
|
||||
RuntimeException exception = new RuntimeException("Async Producer Mock exception");
|
||||
while (!mockProducer.errorNext(exception)) {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
assertThatExceptionOfType(MessageHandlingException.class)
|
||||
.isThrownBy(() -> handler.handleMessage(new GenericMessage<>("foo")))
|
||||
.withMessageContaining("Async Producer Mock exception")
|
||||
.withCauseExactlyInstanceOf(ExecutionException.class)
|
||||
.withRootCauseExactlyInstanceOf(RuntimeException.class);
|
||||
|
||||
handler.setSendTimeout(1);
|
||||
|
||||
assertThatExceptionOfType(MessageTimeoutException.class)
|
||||
.isThrownBy(() -> handler.handleMessage(new GenericMessage<>("foo")))
|
||||
.withMessageContaining("Timeout waiting for response from KafkaProducer")
|
||||
.withCauseExactlyInstanceOf(TimeoutException.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user