java yaml 86 lines · 4 tabs

Custom Spring Boot HealthIndicator for Queue Depth on /actuator/health

Shared by codesnips Aug 2026
4 tabs
package com.example.health;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.stereotype.Component;

@Component("queue")
public class QueueHealthIndicator implements HealthIndicator {

    private final WorkQueueClient queue;
    private final HealthProperties props;

    public QueueHealthIndicator(WorkQueueClient queue, HealthProperties props) {
        this.queue = queue;
        this.props = props;
    }

    @Override
    public Health health() {
        try {
            long depth = queue.pendingCount();
            long oldestAgeMs = queue.oldestMessageAgeMillis();

            Health.Builder builder = depth >= props.maxDepth()
                    ? Health.down()
                    : Health.up();

            return builder
                    .withDetail("depth", depth)
                    .withDetail("warnDepth", props.warnDepth())
                    .withDetail("maxDepth", props.maxDepth())
                    .withDetail("oldestMessageAgeMs", oldestAgeMs)
                    .withDetail("nearingLimit", depth >= props.warnDepth())
                    .build();
        } catch (Exception e) {
            return Health.down()
                    .withDetail("reason", "queue probe failed")
                    .withException(e)
                    .build();
        }
    }
}
4 files · java, yaml Explain with highlit

This snippet shows how a Spring Boot application surfaces an application-specific health signal — the depth of an internal work queue — through the /actuator/health endpoint using a custom HealthIndicator bean. Actuator aggregates every HealthIndicator in the context into the overall status, so registering one bean is enough to make the new signal visible to load balancers, Kubernetes probes, and dashboards without any extra wiring.

In QueueHealthIndicator, the class implements HealthIndicator and overrides health(). The core rule is expressed with the Health builder: below a warning threshold it reports Health.up(), and once the queue backlog crosses a configured limit it reports Health.down(). Regardless of status it attaches contextual detail via withDetail — the current depth, the configured limit, and the oldest-message age — so an operator reading the JSON can see why the component is unhealthy, not just that it is. The indicator is deliberately defensive: any exception from the queue client is caught and converted into Health.down().withException(e) rather than being allowed to propagate, because a health check that throws is worse than one that reports failure.

The thresholds live in HealthProperties, a @ConfigurationProperties bean bound to the app.queue.health prefix. Externalising warnDepth and maxDepth means operators can tune sensitivity per environment through normal Spring configuration instead of recompiling. Binding through a typed record keeps the indicator free of magic numbers.

application.yml completes the picture. It enables @ConfigurationProperties scanning, sets the property values, and — importantly — configures management.endpoint.health.show-details: when-authorized plus a group named readiness that includes only the queue indicator. Grouping matters in Kubernetes: the liveness probe should not fail on a full queue (the process is alive and can recover), while the readiness probe should pull the pod out of rotation until the backlog drains. The trade-off to weigh is that a DOWN component drags the aggregate status to DOWN, so an indicator that is too aggressive can cause needless restarts or traffic loss; choosing warnDepth versus maxDepth and mapping only the right indicators into probe groups is what keeps the signal actionable rather than noisy.


Related snips

go
package api

import (
  "net/http"
  "runtime/debug"
)

Expose build metadata for debugging deploys

go observability build
by Leah Thompson 1 tab
typescript
export interface RetryOptions {
  retries: number;
  baseMs: number;
  maxMs: number;
  signal?: AbortSignal;
  onRetry?: (attempt: number, delay: number, err: unknown) => void;

Exponential backoff with jitter for retries

typescript reliability retry
by codesnips 2 tabs
graphql
type User {
    id: ID!
    name: String!
    email: String!
    posts: [Post!]!
    createdAt: String!

GraphQL API with Spring Boot

java graphql spring-boot
by David Kumar 3 tabs
rust
use tracing::{info, instrument};

#[instrument]
fn process_request(user_id: u64) {
    info!(user_id, "Processing request");
    // Work happens here

tracing for structured logging and distributed tracing

rust observability tracing
by Marcus Chen 1 tab
java
package com.example.starter.config;

import com.example.starter.properties.CustomProperties;
import com.example.starter.service.CustomService;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;

Custom Spring Boot starters

java spring-boot starter
by David Kumar 4 tabs
python
import pandas as pd
from sklearn.ensemble import IsolationForest

df = pd.read_csv('service_metrics.csv')
features = df[['latency_p95', 'error_rate', 'throughput', 'cpu_utilization']]

Anomaly detection with isolation forest and robust thresholds

anomaly-detection isolation-forest monitoring
by Dr. Elena Vasquez 1 tab

Share this code

Here's the card — post it anywhere.

Custom Spring Boot HealthIndicator for Queue Depth on /actuator/health — share card
Link copied