Contents

Writing a Custom Kafka Health Indicator in Spring Boot

In building resilient microservices, health monitoring plays a critical role in ensuring production readiness. Spring Boot Actuator provides powerful health endpoints that integrate seamlessly with orchestration platforms such as Kubernetes, enabling applications to be monitored and managed effectively.

However, a limitation exists: Spring Boot Actuator does not include a built-in Kafka health indicator, unlike the ready-made checks for databases, Redis, and other dependencies. Fortunately, Spring Boot allows developers to define custom health indicators for critical dependencies such as Kafka.


Why Do We Need Health Indicators?

Kubernetes relies on probes to evaluate the health status of applications running in pods. These probes interact with Spring Boot Actuator health endpoints, allowing orchestrators to:

  • Validate Startup using the Startup Probe
  • Assess Liveness using the Liveness Probe
  • Determine Readiness using the Readiness Probe

Without accurate health indicators for critical dependencies such as Kafka, Kubernetes may route traffic to applications that cannot process messages. This can result in data loss, failed message processing, or service downtime. A robust Kafka health check ensures that microservices are genuinely ready and operational from an end-to-end perspective.


Existing Approaches

Many community implementations use KafkaAdmin to verify connectivity to a Kafka broker. This approach attempts broker-level operations to confirm basic Kafka connectivity.

However, broker connectivity alone does not guarantee that both the producer and consumer sides of your application can function correctly. That’s why we’ll take a different approach — extending health indicators to verify producer and consumer workflows.


A Custom Kafka Health Indicator

Depending on your use case, you may implement either or both. For example:

  • A service responsible only for publishing messages may implement a producer health check.
  • A service that primarily processes Kafka messages would benefit more from a consumer health check.
  • In some cases, you may want to combine both for stronger validation.

Coding the Health Indicator

Spring Boot provides a streamlined mechanism for defining custom health indicators by either implementing the HealthIndicator interface or extending the AbstractHealthIndicator base class. For enhanced simplicity and consistency, it is recommended to extend AbstractHealthIndicator, as this abstract class encapsulates the construction of the Health response and offers built-in exception handling. This approach enables developers to focus exclusively on implementing the specific health check logic relevant to their component or subsystem.

Sample Implementation Structure

Create a class named KafkaHealthIndicator that extends AbstractHealthIndicator and annotate it with @Component so that it is registered as a Spring bean:

@Component
public class KafkaHealthIndicator extends AbstractHealthIndicator {

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        // Kafka health check logic
    }
}

Consumer Health Verification

Inject KafkaListenerEndpointRegistry and check the connection-count metric for any one listener to validate consumer connections:

@Autowired
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;

private boolean isConsumerHealthy() {
    Metric metric = kafkaListenerEndpointRegistry.getListenerContainers().stream()
            .flatMap(container -> container.metrics().values().stream())
            .flatMap(metricsMap -> metricsMap.entrySet().stream())
            .filter(entry -> "connection-count".equalsIgnoreCase(entry.getKey().name()))
            .map(Map.Entry::getValue)
            .findFirst()
            .orElseThrow();
    return (Double)metric.metricValue() != 0;
}

Explanation: The KafkaListenerEndpointRegistry tracks consumer metrics across all listeners. The connection-count metric represents the number of active broker connections. A non-zero value confirms that the application’s consumers are live.

Producer Health Verification

Similarly, use the KafkaTemplate bean to check the producer’s connection count:

@Autowired
private KafkaTemplate<String, String> kafkaTemplate;

private boolean isProducerHealthy() {
    Metric metric = kafkaTemplate.metrics().entrySet().stream()
            .filter(es -> "connection-count".equalsIgnoreCase(es.getKey().name()))
            .map(Map.Entry::getValue)
            .findFirst()
            .orElseThrow();
    return (Double)metric.metricValue() != 0;
}

Explanation: By retrieving the producer’s connection-count metric, the health indicator verifies that outbound Kafka connections are active and capable of sending messages.


Final Health Indicator Example

The composite check integrates both producer and consumer validation:

@Component
public class KafkaHealthIndicator extends AbstractHealthIndicator {

    @Autowired
    private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        if (isConsumerHealthy() && isProducerHealthy()) {
            builder.up();
        } else {
            builder.down();
        }
    }

    private boolean isConsumerHealthy() {
        // ...implementation as above
    }

    private boolean isProducerHealthy() {
        // ...implementation as above
    }
}

Configuration: Enabling Health Groups

By default, custom indicators are not included in liveness/readiness probes. To configure them, update application.yml:

management:
  endpoint:
    health:
      probes:
        enabled: true
      group:
        liveness:
          include: kafka
        readiness:
          include: kafka

Note: Spring automatically generates the indicator name by removing HealthIndicator from the class name—thus the indicator is available as kafka.

For enhanced diagnostics, enable detailed output:

management:
  endpoint:
    health:
      probes:
        enabled: true
      show-details: always

This exposes component-level statuses in the health endpoint:

{"components":{"kafka":{"status":"UP"}},"status":"UP"}

Wrapping Up

Spring Boot’s extensibility lets us go beyond the built-in health checks and create Kafka-specific health indicators. These improve the reliability of your service by allowing Kubernetes (or any orchestrator) to make informed decisions about your application’s state.

By verifying both Kafka producer and consumer functionality, your health endpoints more accurately represent the application’s readiness to handle traffic.

When deploying a Spring Boot service that depends on Kafka, avoid relying solely on broker connectivity checks; instead, implement a robust custom health indicator.


You can find the full working sample on GitHub.

Let’s get coding! 🚀