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:
Artem Bilan
2016-07-21 16:58:59 -04:00
committed by Artem Bilan
parent 69cded293f
commit cda52fe966
2 changed files with 102 additions and 5 deletions

View File

@@ -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);
}
}