kafka-streams failed to create state directory on windows - apache-kafka-streams

I am trying to run kafka-streams application on windows machine, however when the application starts it fails to give file permission and ends up with below stack trace.
I have given the custom state directory which has write permission. Has anyone encountered this issue before? I have also tried giving state.dir path under my local user directory but still getting same error.
state.dir = M:\streams
topology.optimization = none
upgrade.from = null
windowstore.changelog.additional.retention.ms = 86400000
2021-05-21 02:54:39.729 INFO 12060 --- [ main] o.a.k.s.KafkaStreams : stream-client [test-admin-stream-9bccb29d-b515-4e96-8e05-0fc20614be7e] Kafka Streams version: 2.6.1
2021-05-21 02:54:39.730 INFO 12060 --- [ main] o.a.k.s.KafkaStreams : stream-client [test-admin-stream-9bccb29d-b515-4e96-8e05-0fc20614be7e] Kafka Streams commit ID: 6b2021cd52659cef
2021-05-21 02:54:39.851 INFO 12060 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-05-21 02:54:39.912 ERROR 12060 --- [ main] o.s.b.SpringApplication : Application run
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:822) [spring-boot-2.4.5.jar:2.4.5]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:803) [spring-boot-2.4.5.jar:2.4.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:346) [spring-boot-2.4.5.jar:2.4.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340) [spring-boot-2.4.5.jar:2.4.5]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) [spring-boot-2.4.5.jar:2.4.5]
at com.pb.testadmin.testAdminApplication.main(testAdminApplication.java:10) [classes/:?]
Caused by: java.lang.UnsupportedOperationException
at java.nio.file.Files.setPosixFilePermissions(Files.java:2079) ~[?:?]
at org.apache.kafka.streams.processor.internals.StateDirectory.<init>(StateDirectory.java:115) ~[kafka-streams-2.6.1.jar:?]
at org.apache.kafka.streams.KafkaStreams.<init>(KafkaStreams.java:745) ~[kafka-streams-2.6.1.jar:?]
at org.apache.kafka.streams.KafkaStreams.<init>(KafkaStreams.java:657) ~[kafka-streams-2.6.1.jar:?]
at org.apache.kafka.streams.KafkaStreams.<init>(KafkaStreams.java:567) ~[kafka-streams-2.6.1.jar:?]
at com.pb.testadmin.consumer.ForexStream.run(ForexStream.java:55) ~[classes/:?]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:819) ~[spring-boot-2.4.5.jar:2.4.5]
Below is code snippet of streams.
props.put(StreamsConfig.STATE_DIR_CONFIG, "M:\\streams");
final StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> leftSource = builder.stream("REQ");
KStream<String, String> rightSource = builder.stream("RESP");
KStream<String, String> joined = leftSource.join(rightSource, (leftValue, rightValue) -> "left=" + leftValue + ", right=" + rightValue,
JoinWindows.of(Duration.ofMinutes(1)),
Joined.with(Serdes.String(), Serdes.String(), Serdes.String())
);
joined.to("test");
final Topology topology = builder.build();
streamsInnerJoin = new KafkaStreams(topology, props);
streamsInnerJoin.start();

Looks like it was a bug in Kafka 2.7.0 and 2.6.1. It should be fixed in
2.8.0, 2.7.1, 2.6.2

Related

Spring Boot 3 fails to generate native image when having Avro as a dependency

I'm running ./gradlew nativeCompile to generate a native image on a project that has implementation("org.apache.avro:avro:1.11.1") as a dependency, with the following exception:
2022-12-19T12:29:21.693+01:00 INFO [metrics,,] 81039 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Pre-creating binder child context (AOT) for kstream
2022-12-19T12:29:21.695+01:00 INFO [metrics,,] 81039 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Pre-creating binder child context (AOT) for ktable
2022-12-19T12:29:21.696+01:00 INFO [metrics,,] 81039 --- [ main] o.s.c.s.binder.DefaultBinderFactory : Pre-creating binder child context (AOT) for globalktable
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.startsWith(String)" because the return value of "java.lang.Class.getCanonicalName()" is null
at org.springframework.aot.hint.BindingReflectionHintsRegistrar.shouldSkipMembers(BindingReflectionHintsRegistrar.java:75)
at org.springframework.aot.hint.BindingReflectionHintsRegistrar.lambda$registerReflectionHints$0(BindingReflectionHintsRegistrar.java:88)
at org.springframework.aot.hint.ReflectionHints.registerType(ReflectionHints.java:86)
at org.springframework.aot.hint.ReflectionHints.registerType(ReflectionHints.java:109)
at org.springframework.aot.hint.BindingReflectionHintsRegistrar.registerReflectionHints(BindingReflectionHintsRegistrar.java:87)
at org.springframework.aot.hint.BindingReflectionHintsRegistrar.registerReflectionHints(BindingReflectionHintsRegistrar.java:65)
at org.springframework.data.util.TypeContributor.contribute(TypeContributor.java:70)
at org.springframework.data.util.TypeContributor.contribute(TypeContributor.java:82)
at org.springframework.data.aot.ManagedTypesBeanRegistrationAotProcessor.contributeType(ManagedTypesBeanRegistrationAotProcessor.java:137)
at org.springframework.data.mongodb.aot.MongoManagedTypesBeanRegistrationAotProcessor.contributeType(MongoManagedTypesBeanRegistrationAotProcessor.java:53)
at org.springframework.data.aot.ManagedTypesRegistrationAotContribution.lambda$applyTo$0(ManagedTypesRegistrationAotContribution.java:97)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:104)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:118)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:118)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:118)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:118)
at org.springframework.data.util.TypeCollector.processType(TypeCollector.java:118)
at org.springframework.data.util.TypeCollector.process(TypeCollector.java:91)
at org.springframework.data.util.TypeCollector$ReachableTypes.lambda$forEach$0(TypeCollector.java:217)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.springframework.data.util.TypeCollector$ReachableTypes.forEach(TypeCollector.java:217)
at org.springframework.data.aot.ManagedTypesRegistrationAotContribution.applyTo(ManagedTypesRegistrationAotContribution.java:97)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.lambda$generateBeanDefinitionMethod$2(BeanDefinitionMethodGenerator.java:179)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:178)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:102)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateRegisterBeanDefinitionsMethod$2(BeanRegistrationsAotContribution.java:85)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterBeanDefinitionsMethod(BeanRegistrationsAotContribution.java:83)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$applyTo$1(BeanRegistrationsAotContribution.java:67)
at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:66)
at org.springframework.context.aot.BeanFactoryInitializationAotContributions.applyTo(BeanFactoryInitializationAotContributions.java:78)
at org.springframework.context.aot.ApplicationContextAotGenerator.lambda$processAheadOfTime$0(ApplicationContextAotGenerator.java:58)
at org.springframework.context.aot.ApplicationContextAotGenerator.withCglibClassHandler(ApplicationContextAotGenerator.java:67)
at org.springframework.context.aot.ApplicationContextAotGenerator.processAheadOfTime(ApplicationContextAotGenerator.java:53)
at org.springframework.context.aot.ContextAotProcessor.performAotProcessing(ContextAotProcessor.java:106)
at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:84)
at org.springframework.context.aot.ContextAotProcessor.doProcess(ContextAotProcessor.java:49)
at org.springframework.context.aot.AbstractAotProcessor.process(AbstractAotProcessor.java:82)
at org.springframework.boot.SpringApplicationAotProcessor.main(SpringApplicationAotProcessor.java:76)
> Task :processAot FAILED
The exception happens in BindingReflectionHintsRegistrar.shouldSkipMembers(...)--> type.getCanonicalName():
private boolean shouldSkipMembers(Class<?> type) {
return type.getCanonicalName().startsWith("java.") || type.isArray();
}
The type that generates the NullPointer is class org.apache.avro.JsonProperties$1.
How can this be fixed?
This particular NullPointerException has been solved in this issue, the fix has been released with Spring Framework 6.0.3.

spring boot kafka failed with "Broker may not be available" while using testcontainers with kafka, zookeeper, schema registry

I've run testcontainers like below in the test code.
#Testcontainers
public class TestEnvironmentSupport {
static String version = "5.4.0";
static DockerImageName kafkaImage = DockerImageName.parse("confluentinc/cp-server").withTag(version);
static DockerImageName zookeeperImage = DockerImageName.parse("confluentinc/cp-zookeeper").withTag(version);
static DockerImageName schemaRegistryImage = DockerImageName.parse("confluentinc/cp-schema-registry").withTag(version);
static Network network = Network.newNetwork();
#Container
static GenericContainer zookeeper = new GenericContainer<>(zookeeperImage)
.withNetwork(network)
.withCreateContainerCmdModifier(cmd -> cmd.withHostName("zookeeper"))
.withExposedPorts(2181)
.withEnv("ZOOKEEPER_CLIENT_PORT", "2181")
.withEnv("ZOOKEEPER_TICK_TIME", "2000");
#Container
static GenericContainer kafka = new GenericContainer<>(kafkaImage)
.withNetwork(network)
.withCreateContainerCmdModifier(cmd -> cmd.withHostName("kafka"))
.withExposedPorts(9092)
.dependsOn(zookeeper)
.withEnv("KAFKA_BROKER_ID", "1")
.withEnv("KAFKA_ZOOKEEPER_CONNECT", "zookeeper:2181")
.withEnv("KAFKA_LISTENER_SECURITY_PROTOCOL_MAP", "PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT")
.withEnv("KAFKA_ADVERTISED_LISTENERS", "PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092")
.withEnv("KAFKA_CONFLUENT_SCHEMA_REGISTRY_URL", "schema-registry:8081");
#Container
static GenericContainer schemaRegistry = new GenericContainer<>(schemaRegistryImage)
.withNetwork(network)
.withCreateContainerCmdModifier(cmd -> cmd.withHostName("schema-registry"))
.withExposedPorts(8081)
.dependsOn(zookeeper, kafka)
.withEnv("SCHEMA_REGISTRY_HOST_NAME", "schema-registry")
.withEnv("SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL", "zookeeper:2181");
#Test
void test() {
assertTrue(zookeeper.isRunning());
assertTrue(kafka.isRunning());
assertTrue(schemaRegistry.isRunning());
}
}
and it works totally fine.
But the problem occurred when I tried to run spring boot test with the above testcontainer configuration because testcontainer dynamically generates broker ports but NetworkClient continuously accessing the broker with localhost:9092 even though I dynamically override properties on #SpringBootTest code like below
#DynamicPropertySource
static void testcontainerProperties(final DynamicPropertyRegistry registry) {
var bootstrapServers = kafka.getHost() + ":" + kafka.getMappedPort(9092);
var schemaRegistryUrl = "http://" + schemaRegistry.getHost() + ":" + schemaRegistry.getMappedPort(8081);
registry.add("spring.cloud.stream.kafka.binder.brokers", () -> bootstrapServers);
registry.add("bootstrap.servers", () -> bootstrapServers);
registry.add("schema.registry.url", () -> schemaRegistryUrl);
registry.add("spring.cloud.stream.kafka.default.consumer.configuration.schema.registry.url", () -> schemaRegistryUrl);
}
Below is AdminClientConfig log on startup time, and it shows that bootstrap.servers = [localhost:56001] on which the port is dynamically binded by testcontainer.
2021-02-21 20:28:52.291 INFO 78241 --- [ Test worker] o.a.k.clients.admin.AdminClientConfig : AdminClientConfig values:
bootstrap.servers = [localhost:56013]
client.dns.lookup = use_all_dns_ips
Even though I set like these it keeps trying to connect to localhost:9092 like below.
2021-02-21 20:28:52.457 INFO 78241 --- [ Test worker] o.a.kafka.common.utils.AppInfoParser : Kafka startTimeMs: 1613906932454
2021-02-21 20:28:53.095 WARN 78241 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node 1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
2021-02-21 20:28:53.202 WARN 78241 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node 1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
2021-02-21 20:28:53.407 WARN 78241 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node 1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
And below is the result of docker ps while running spring boot test.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e340d9e15fe4 confluentinc/cp-schema-registry:5.4.0 "/etc/confluent/dock…" 46 seconds ago Up 46 seconds 0.0.0.0:56014->8081/tcp optimistic_joliot
ad3bf06df4b3 confluentinc/cp-server:5.4.0 "/etc/confluent/dock…" 55 seconds ago Up 54 seconds 0.0.0.0:56013->9092/tcp infallible_brown
f7fa5f4ae23c confluentinc/cp-zookeeper:5.4.0 "/etc/confluent/dock…" About a minute ago Up 59 seconds 0.0.0.0:56012->2181/tcp, 0.0.0.0:56011->2888/tcp, 0.0.0.0:56010->3888/tcp agitated_leavitt
b1c036cdf00b testcontainers/ryuk:0.3.0 "/app" About a minute ago Up About a minute 0.0.0.0:56009->8080/tcp testcontainers-ryuk-68190eaa-8513-4dd8-ab67-175275f15a82
I tried run testcontainers with docker compose module but it has the same issue.
What am I doing wrong?
Please help.
It's trying to connect to localhost:9092 because you've tried to connect to the advertised PLAINTEXT_HOST port, and that's the address it'll return. You shouldn't need to advertise two listeners for tests, so try using kafka:29092 directly instead of calling the mapped port method. Also, unless you have a specific need for server-side schema validation, you only need confluentinc/cp-kafka image.
spring-kafka embedded broker should work your tests, too, so you wouldn't need testcontainers

Enabling exactly once causes streams shutdown due to timeout while initializing transactional state

I've written a simple example to test the join functionality. As I sometimes get messages duplicated in the resulting topic and sometimes missing messages in this topic, I thought while pinpointing the problem to enable exactly once semantics. However while doing this through:
props.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE);
I get a timeout that causes kafka streams to shut down in my app:
2019-05-02 17:02:32.585 INFO 153056 --- [-StreamThread-1] o.a.kafka.common.utils.AppInfoParser : Kafka version : 2.0.1
2019-05-02 17:02:32.585 INFO 153056 --- [-StreamThread-1] o.a.kafka.common.utils.AppInfoParser : Kafka commitId : fa14705e51bd2ce5
2019-05-02 17:02:32.593 INFO 153056 --- [-StreamThread-1] o.a.k.c.p.internals.TransactionManager : [Producer clientId=join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1-0_0-producer, transactionalId=join-test-0_0] ProducerId set to -1 with epoch -1
2019-05-02 17:03:32.599 ERROR 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] Error caught during partition assignment, will abort the current process and re-throw at the end of rebalance: {}
org.apache.kafka.common.errors.TimeoutException: Timeout expired while initializing transactional state in 60000ms.
2019-05-02 17:03:32.599 INFO 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] partition assignment took 60044 ms.
current active tasks: []
current standby tasks: []
previous active tasks: []
2019-05-02 17:03:32.601 INFO 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] State transition from PARTITIONS_ASSIGNED to PENDING_SHUTDOWN
2019-05-02 17:03:32.601 INFO 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] Shutting down
2019-05-02 17:03:32.615 INFO 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] State transition from PENDING_SHUTDOWN to DEAD
2019-05-02 17:03:32.615 INFO 153056 --- [-StreamThread-1] org.apache.kafka.streams.KafkaStreams : stream-client [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72] State transition from REBALANCING to ERROR
2019-05-02 17:03:32.615 WARN 153056 --- [-StreamThread-1] org.apache.kafka.streams.KafkaStreams : stream-client [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72] All stream threads have died. The instance will be in error state and should be closed.
2019-05-02 17:03:32.615 INFO 153056 --- [-StreamThread-1] o.a.k.s.p.internals.StreamThread : stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] Shutdown complete
Exception in thread "join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1" org.apache.kafka.streams.errors.StreamsException: stream-thread [join-test-90a0aa93-dfd8-4d4f-894b-85a3c5634f72-StreamThread-1] Failed to rebalance.
at org.apache.kafka.streams.processor.internals.StreamThread.pollRequests(StreamThread.java:870)
at org.apache.kafka.streams.processor.internals.StreamThread.runOnce(StreamThread.java:810)
at org.apache.kafka.streams.processor.internals.StreamThread.runLoop(StreamThread.java:767)
at org.apache.kafka.streams.processor.internals.StreamThread.run(StreamThread.java:736)
Caused by: org.apache.kafka.common.errors.TimeoutException: Timeout expired while initializing transactional state in 60000ms.
static String ORIGINAL = "original-sensor-data";
static String ERROR = "error-score";
public static void main(String[] args) throws IOException {
SpringApplication.run(JoinTest.class, args);
Properties props = getProperties();
final StreamsBuilder builder = new StreamsBuilder();
final KStream<String, OriginalSensorData> original = builder.stream(ORIGINAL, Consumed.with(Serdes.String(), new OriginalSensorDataSerde()));
final KStream<String, ErrorScore> error = builder.stream(ERROR, Consumed.with(Serdes.String(), new ErrorScoreSerde()));
KStream<String, ErrorScore> result = original.join(
error,
(originalValue, errorValue) -> new ErrorScore(new Date(originalValue.getTimestamp()), errorValue.getE(),
originalValue.getData().get("TE700PV").doubleValue(), errorValue.getT(), errorValue.getR()),
// KStream-KStream joins are always windowed joins, hence we must provide a join window.
JoinWindows.of(Duration.ofMillis(3000).toMillis()),
Joined.with(
Serdes.String(), /* key */
new OriginalSensorDataSerde(), /* left value */
new ErrorScoreSerde() /* right value */
)
).through("atl-joined-data-repartition", Produced.with(Serdes.String(), new ErrorScoreSerde()));
result.foreach((key, value) -> System.out.println("Join Stream: " + key + " " + value));
KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();
}
private static Properties getProperties() {
Properties props = new Properties();
//Url of the kafka broker, this can also be found in the Aiven console
props.put("bootstrap.servers", "localhost:9095");
props.put("group.id", "join-test");
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
props.put("application.id", "join-test");
props.put("default.timestamp.extractor", "com.my.SensorDataTimestampExtractor");
//The key of a message is a string
props.put("key.deserializer",
StringDeserializer.class.getName());
props.put("value.deserializer",
StringDeserializer.class.getName());
props.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE);
props.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 1000);
return props;
}
I'm expecting that the app starts without the timeout and continues working

AWS Lambda - Spring boot is not handling the request

I am trying to run spring boot application as serverless in AWS lambda and I am getting below exception while calling lambda function. Spring boot application successfully ran but it seems that it is going to fail to map the request
2018-09-25 06:11:50.717 INFO 1 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-09-25 06:11:50.823 INFO 1 --- [ main] **my.service.Application : Started Application in 7.405 seconds (JVM running for 8.939)**
START RequestId: decfc13c-c089-11e8-bacd-a37f1ba65629 Version: $LATEST
2018-09-25 06:11:50.994 ERROR 1 --- [ main] **c.a.s.p.i.s.AwsProxyHttpServletRequest : Called set character encoding to UTF-8 on a request without a content type. Character encoding will not be set
2018-09-25 06:11:51.175 ERROR 1 --- [ main] o.s.boot.web.support.ErrorPageFilter : Forwarding to error page from request [/] due to exception [null]**
java.lang.NullPointerException: null
at com.amazonaws.serverless.proxy.internal.servlet.AwsProxyHttpServletRequest.getRemoteAddr(AwsProxyHttpServletRequest.java:575) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.publishRequestHandledEvent(FrameworkServlet.java:1075) ~[task/:na]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[task/:na]
.........
2018-09-25 06:11:51.535 ERROR 1 --- [ main] s.p.i.s.AwsLambdaServletContainerHandler : Could not forward request
This is my StreamLambdaHandler java file.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(Application.class);
} catch (ContainerInitializationException e) {
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
#Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
outputStream.close();
}
}
Looks like you might be hitting https://github.com/awslabs/aws-serverless-java-container/issues/172. According to the ticket, the fix will be available as part of the upcoming 1.2 release.

MongoDB change stream replica set recovery

I implemented MongoDB change streams with Spring and it works fine when the replica set primary node is up.
#Service
public class ChangeEventService {
private static final Logger logger = LoggerFactory.getLogger(ChangeEventService.class);
private final MongoClient mongoClient;
public ChangeEventService(MongoClient mongoClient) {
this.mongoClient = mongoClient;
}
#PostConstruct
public void subscribe() {
MongoDatabase db = mongoClient.getDatabase("experiment");
MongoCollection<Document> collection = db.getCollection("debug");
Block<ChangeStreamDocument<Document>> printBlock = changeStreamDocument -> {
logger.info("Received: {}", changeStreamDocument.getFullDocument().toString());
BsonDocument resumeToken = changeStreamDocument.getResumeToken();
};
collection.watch().forEach(printBlock);
logger.info("Consumer is ready to process");
}
}
Then I shut down the primary node of the replica set. I was expecting the change stream to wait for the replica set to elect a new primary and continue to get the data changes. The actual behavior is an application crash.
From the logs I can see that the connection to the primary (27000) is closed which is expected, then it seems to try to open a connection to one of the secondary (27001) but can't because the pool has been closed.
From the documentation: "The change stream is bound to a collection and change stream documents are iterated with a cursor. This cursor remains open until it is explicitly closed, as long as a connection to the MongoDB deployment remains open and the collection exists."
2018-05-02 12:03:03.424 INFO 9560 --- [ main] c.e.m.service.ChangeEventService : Received: Document{{_id=5ae98cd7dcc8921c94d5f9e5, _class=com.mongodb.BasicDBObject, uuid=4f836d00-efc3-4d48-956a-af4dbfed90e7, now=Wed May 02 12:03:03 CEST 2018}}
2018-05-02 12:03:06.500 WARN 9560 --- [ main] org.mongodb.driver.connection : Got socket exception on connection [connectionId{localValue:4, serverValue:8}] to localhost:27000. All connections to localhost:27000 will be closed.
2018-05-02 12:03:06.501 INFO 9560 --- [ main] org.mongodb.driver.connection : Closed connection [connectionId{localValue:4, serverValue:8}] to localhost:27000 because there was a socket exception raised by this connection.
2018-05-02 12:03:07.502 INFO 9560 --- [ main] org.mongodb.driver.connection : Closed connection [connectionId{localValue:6}] to localhost:27000 because there was a socket exception raised by this connection.
2018-05-02 12:03:07.504 WARN 9560 --- [ main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'changeEventService': Invocation of init method failed; nested exception is com.mongodb.MongoSocketOpenException: Exception opening socket
2018-05-02 12:03:07.505 INFO 9560 --- [localhost:27000] org.mongodb.driver.cluster : Exception in monitor thread while connecting to server localhost:27000
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.connection.SocketStream.open(SocketStream.java:62) ~[mongodb-driver-core-3.6.3.jar:na]
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:126) ~[mongodb-driver-core-3.6.3.jar:na]
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:128) ~[mongodb-driver-core-3.6.3.jar:na]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ~[na:1.8.0_161]
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:85) ~[na:1.8.0_161]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_161]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_161]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_161]
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172) ~[na:1.8.0_161]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_161]
at java.net.Socket.connect(Socket.java:589) ~[na:1.8.0_161]
at com.mongodb.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:59) ~[mongodb-driver-core-3.6.3.jar:na]
at com.mongodb.connection.SocketStream.open(SocketStream.java:57) ~[mongodb-driver-core-3.6.3.jar:na]
... 3 common frames omitted
2018-05-02 12:03:07.507 INFO 9560 --- [ main] org.mongodb.driver.connection : Opened connection [connectionId{localValue:7, serverValue:181}] to localhost:27001
2018-05-02 12:03:07.508 INFO 9560 --- [ main] org.mongodb.driver.connection : Closed connection [connectionId{localValue:7, serverValue:181}] to localhost:27001 because the pool has been closed.
2018-05-02 12:03:07.511 INFO 9560 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2
There are two things here:
at com.mongodb.connection.SocketStream.open(SocketStream.java:57) ~[mongodb-driver-core-3.6.3.jar:na]
There is a bug with MongoDB Java driver v3.6.3, where change streams cursor does not resume when there's an attempt to kill the existing cursor fails. This is described in JAVA-2821, and fixed in version 3.7.0 onwards.
collection.watch().forEach(printBlock);
The watch() method does't actually contact the server, instead you should use an iterator method. For example:
MongoCursor<ChangeStreamDocument<Document>> cursor = collection.watch().iterator();
ChangeStreamDocument<Document> next = cursor.next();
while(cursor.hasNext()){
next = cursor.next();
System.out.println(next);
}
See also Spec: Resumable Error for the definition of error that is considered resumable.

Resources