java 50 lines · 7 steps

A custom replica health check in Spring

A Spring Actuator HealthIndicator that probes a read replica and reports UP, DEGRADED, or DOWN based on latency.

Explained by highlit
1package com.example.monitoring;
2 
3import org.springframework.boot.actuate.health.Health;
4import org.springframework.boot.actuate.health.HealthIndicator;
5import org.springframework.stereotype.Component;
6 
7import javax.sql.DataSource;
8import java.sql.Connection;
9import java.time.Duration;
10import java.time.Instant;
11 
12@Component("replicaDatabase")
13public class ReplicaDatabaseHealthIndicator implements HealthIndicator {
14 
15 private static final Duration SLOW_THRESHOLD = Duration.ofMillis(250);
16 
17 private final DataSource replicaDataSource;
18 
19 public ReplicaDatabaseHealthIndicator(DataSource replicaDataSource) {
20 this.replicaDataSource = replicaDataSource;
21 }
22 
23 @Override
24 public Health health() {
25 Instant start = Instant.now();
26 try (Connection connection = replicaDataSource.getConnection()) {
27 boolean valid = connection.isValid((int) SLOW_THRESHOLD.toSeconds() + 1);
28 Duration elapsed = Duration.between(start, Instant.now());
29 
30 if (!valid) {
31 return Health.down()
32 .withDetail("reason", "replica connection failed validation")
33 .build();
34 }
35 
36 Health.Builder builder = elapsed.compareTo(SLOW_THRESHOLD) > 0
37 ? Health.status("DEGRADED")
38 : Health.up();
39 
40 return builder
41 .withDetail("latencyMs", elapsed.toMillis())
42 .withDetail("catalog", connection.getCatalog())
43 .build();
44 } catch (Exception ex) {
45 return Health.down(ex)
46 .withDetail("reason", "unable to reach replica")
47 .build();
48 }
49 }
50}
01 / 01
STEP 01

Walkthrough

Space play ←→ step click any line
Three takeaways
  1. 1Implementing HealthIndicator lets you fold custom probes into Actuator's aggregated health endpoint.
  2. 2A health check can report graded status, not just up or down, by distinguishing slow from failed.
  3. 3Try-with-resources guarantees the probe connection is returned even when validation or the query throws.

Related explainers

java
@Component
@Converter
public class EncryptedStringConverter implements AttributeConverter<String, String> {
 

Transparent column encryption in Spring & JPA

encryption aes-gcm jpa-converter
Advanced 10 steps
java
package com.acme.billing.config;
 
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;

Feature-flagged beans with Spring @ConditionalOnProperty

feature-flags conditional-beans strategy-pattern
Intermediate 5 steps
java
public static Map<String, String> parseCookieHeader(String header) {
    Map<String, String> cookies = new LinkedHashMap<>();
    if (header == null || header.isBlank()) {
        return cookies;

Parsing an HTTP Cookie header in Java

string-parsing http url-decoding
Intermediate 6 steps
java
public class TimedSocketReader {
 
    private static final int READ_TIMEOUT_MS = 5_000;
    private static final int CONNECT_TIMEOUT_MS = 3_000;

Reading a socket with connect and read timeouts

sockets timeouts io
Intermediate 8 steps
java
public final class EncodingDetector {
 
    public enum Encoding {
        UTF_8, UTF_16LE, UTF_16BE, UTF_32LE, UTF_32BE, ASCII, UNKNOWN

Detecting text encoding from raw bytes in Java

byte-manipulation encoding-detection bitwise-operations
Intermediate 8 steps
java
public final class ImportOrganizer {
 
    private static final Pattern IMPORT_LINE =
            Pattern.compile("^import\\s+(static\\s+)?([\\w.]+(?:\\.\\*)?)\\s*;\\s*$");

Sorting Java imports with a regex pass

regex sorting text-processing
Intermediate 8 steps

Share this explainer

Here's the card — post it anywhere.

A custom replica health check in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code