Describe the issue
After querying the Kafka bindings actuator endpoint, stopping and starting a consumer binding causes the Kafka listener container to fail when it receives the next record. The record is not delivered to the application consumer.
The issue appears to be related to the workaround introduced for #3167. That workaround replaces the container's ObservationRegistry with a null implementation while serializing binding properties. The same container is subsequently restarted with that registry, and Micrometer fails when creating the Kafka observation because observationConfig() returns null.
A minimal reproducer is available here:
https://github.com/ferblaca/demoSCSKafka/tree/actuator-rebalance-issue
To Reproduce
-
Clone the reproducer and check out the actuator-rebalance-issue branch.
-
Start the Kafka and ZooKeeper services using the Docker Compose configuration.
-
Start the Spring Boot application.
-
Query the bindings actuator endpoint:
curl http://localhost:8080/demo-stream-kafka/stream/bindings
-
Stop the consumer binding programmatically:
curl -X POST http://localhost:8080/demo-stream-kafka/repro/stop
-
Start the consumer binding programmatically:
curl -X POST http://localhost:8080/demo-stream-kafka/repro/start
-
Send a message to the Kafka destination:
curl -X POST http://localhost:8080/demo-stream-kafka/repro/send
-
Observe the application log. The message is sent successfully, but the consumer callback is not invoked and the listener container reports the following error:
java.lang.IllegalStateException: This error handler cannot process 'java.lang.NullPointerException's; no record information is available
at org.springframework.kafka.listener.DefaultErrorHandler.handleOtherException(DefaultErrorHandler.java:198) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.handleConsumerException(KafkaMessageListenerContainer.java:2139) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:1436) ~[spring-kafka-4.1.1.jar:4.1.1]
at java.base/java.util.concurrent.CompletableFuture$AsyncRun.run(CompletableFuture.java:1825) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1474) ~[na:na]
Caused by: java.lang.NullPointerException: Cannot invoke \"io.micrometer.observation.ObservationRegistry$ObservationConfig.getObservationConvention(io.micrometer.observation.Observation$Context, io.micrometer.observation.ObservationConvention)\" because the return value of \"io.micrometer.observation.ObservationRegistry.observationConfig()\" is null
at io.micrometer.observation.Observation.createNotStarted(Observation.java:248) ~[micrometer-observation-1.17.1.jar:1.17.1]
at io.micrometer.observation.docs.ObservationDocumentation.observation(ObservationDocumentation.java:186) ~[micrometer-observation-1.17.1.jar:1.17.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:2977) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:2806) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:2692) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:2323) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeIfHaveRecords(KafkaMessageListenerContainer.java:1621) ~[spring-kafka-4.1.1.jar:4.1.1]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:1523) ~[spring-kafka-4.1.1.jar:4.1.1]
Version of the framework
- Spring Boot 4.1.1
- Spring Cloud Stream 5.0.3
- Spring Kafka 4.1.1
- Micrometer Observation 1.17.1
- Java 25.0.2
Expected behavior
Querying the bindings actuator endpoint must not modify the observation configuration of an active Kafka consumer container. After stopping and starting the binding, the consumer should continue to process records successfully without an exception in the listener container.
Screenshots
Not applicable.
Additional context
The reproducer indicates that the failure is triggered by this sequence:
- Query bindings actuator endpoint.
- Stop and start a Kafka consumer binding.
- Publish a record.
Without querying the bindings endpoint, the consumer processes records normally. The suspected regression is related to the fix for #3167.
Describe the issue
After querying the Kafka bindings actuator endpoint, stopping and starting a consumer binding causes the Kafka listener container to fail when it receives the next record. The record is not delivered to the application consumer.
The issue appears to be related to the workaround introduced for #3167. That workaround replaces the container's
ObservationRegistrywith a null implementation while serializing binding properties. The same container is subsequently restarted with that registry, and Micrometer fails when creating the Kafka observation becauseobservationConfig()returnsnull.A minimal reproducer is available here:
https://github.com/ferblaca/demoSCSKafka/tree/actuator-rebalance-issue
To Reproduce
Clone the reproducer and check out the
actuator-rebalance-issuebranch.Start the Kafka and ZooKeeper services using the Docker Compose configuration.
Start the Spring Boot application.
Query the bindings actuator endpoint:
Stop the consumer binding programmatically:
Start the consumer binding programmatically:
Send a message to the Kafka destination:
Observe the application log. The message is sent successfully, but the consumer callback is not invoked and the listener container reports the following error:
Version of the framework
Expected behavior
Querying the bindings actuator endpoint must not modify the observation configuration of an active Kafka consumer container. After stopping and starting the binding, the consumer should continue to process records successfully without an exception in the listener container.
Screenshots
Not applicable.
Additional context
The reproducer indicates that the failure is triggered by this sequence:
Without querying the bindings endpoint, the consumer processes records normally. The suspected regression is related to the fix for #3167.