tutorial

Monitoring Helidon Microservices with Vigilmon

Oracle's Helidon framework exposes MicroProfile Health and Metrics endpoints out of the box — here's how to wire them into Vigilmon for liveness probes, latency alerting, fault tolerance monitoring, and GraalVM native image health checks.

Helidon is an open source Java microservices framework developed by Oracle and released in 2018. It comes in two flavors: Helidon SE (reactive, functional, built on Java 21 virtual threads) and Helidon MP (MicroProfile-compliant, with standard CDI/JAX-RS APIs). Both expose rich built-in health and metrics endpoints that make external monitoring straightforward. Vigilmon connects to those built-in endpoints to give you liveness and readiness alerting, latency SLA enforcement, fault tolerance visibility, and GraalVM native image startup regression detection — without instrumenting your application code.

What You'll Set Up

  • Liveness and readiness probe monitors (/health/live and /health/ready)
  • MicroProfile Metrics endpoint availability check
  • Request latency SLA alerting
  • Circuit breaker state monitoring via health indicators
  • Database connection pool exhaustion alerting
  • GraalVM native image startup regression check
  • JVM heap and GC pause alerting via heartbeat

Prerequisites

  • Helidon MP 4.x or Helidon SE 4.x running on Java 21+
  • MicroProfile Health and Metrics dependencies included (default in Helidon MP starters)
  • Network access from Vigilmon to your Helidon service
  • A free Vigilmon account

Step 1: Monitor Helidon Liveness and Readiness Probes

Helidon MP automatically exposes MicroProfile Health endpoints at /health/live and /health/ready. These return 200 UP or 503 DOWN depending on the aggregated health checks registered in your application. Add monitors for both:

Liveness probe:

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter: http://your-helidon-service:8080/health/live.
  4. Set Expected HTTP status to 200.
  5. Set Check interval to 1 minute.
  6. Click Save.

Readiness probe:

Repeat with /health/ready. A readiness failure means the service is alive but not ready to serve traffic — useful for detecting cold-start delays, failed dependency connections, or in-progress warmup.

If you're running under Kubernetes, Helidon's health endpoints align with Kubernetes liveness and readiness probe conventions — Vigilmon gives you the same signal from outside the cluster.


Step 2: Monitor the MicroProfile Metrics Endpoint

Helidon MP exposes application metrics at /metrics. If this endpoint goes down, your observability pipeline loses visibility into the application's internal state. Add a monitor:

  1. Click Add Monitor.
  2. Set Type to HTTP / HTTPS with Keyword check.
  3. Enter: http://your-helidon-service:8080/metrics.
  4. Set Keyword to "base" (the base metrics scope is always present in MicroProfile Metrics).
  5. Set Check interval to 2 minutes.
  6. Click Save.

This confirms the metrics endpoint is responding and returning a valid Prometheus-format body.


Step 3: Monitor Request Throughput and Latency

Helidon automatically tracks HTTP request metrics. You can expose a custom latency health indicator that returns degraded status when p99 latency exceeds your SLA:

@ApplicationScoped
@Liveness
public class LatencyHealthCheck implements HealthCheck {

  @Inject
  private MeterRegistry meterRegistry;

  @Override
  public HealthCheckResponse call() {
    Timer requestTimer = meterRegistry.timer("http.server.requests");
    double p99Ms = requestTimer.percentileValues()
        .stream()
        .filter(v -> v.percentile() == 0.99)
        .mapToDouble(v -> v.value(TimeUnit.MILLISECONDS))
        .findFirst()
        .orElse(0);

    return p99Ms < 500
        ? HealthCheckResponse.up("latency")
        : HealthCheckResponse.down("latency")
            .withData("p99Ms", p99Ms)
            .build();
  }
}

Vigilmon will detect the 503 response when p99 latency breaches 500ms and trigger an alert.


Step 4: Monitor Fault Tolerance Health

MicroProfile Fault Tolerance annotations (@CircuitBreaker, @Retry, @Bulkhead, @Timeout) protect Helidon services from downstream failures. An open circuit breaker means a downstream dependency is failing. Register a health indicator:

@ApplicationScoped
@Liveness
public class FaultToleranceHealthCheck implements HealthCheck {

  @Inject
  private CircuitBreakerStateTracker cbTracker;

  @Override
  public HealthCheckResponse call() {
    boolean anyOpen = cbTracker.getOpenCircuitBreakers().size() > 0;
    
    HealthCheckResponseBuilder builder = anyOpen
        ? HealthCheckResponse.named("fault-tolerance").down()
        : HealthCheckResponse.named("fault-tolerance").up();
    
    cbTracker.getOpenCircuitBreakers().forEach(cb ->
        builder.withData(cb.getName(), "OPEN"));
    
    return builder.build();
  }
}

This surfaces in the /health/live endpoint. Vigilmon's liveness monitor from Step 1 will catch it automatically.


Step 5: Monitor Database Connection Pool Health

Helidon applications typically use HikariCP for database connections. Pool exhaustion causes immediate request failures. Add a custom health check for connection pool state:

@ApplicationScoped
@Readiness
public class DataSourceHealthCheck implements HealthCheck {

  @Inject
  private HikariDataSource dataSource;

  @Override
  public HealthCheckResponse call() {
    HikariPoolMXBean pool = dataSource.getHikariPoolMXBean();
    int pending = pool.getThreadsAwaitingConnection();
    int active = pool.getActiveConnections();
    int max = dataSource.getMaximumPoolSize();

    boolean healthy = pending == 0 && active < max;

    return healthy
        ? HealthCheckResponse.named("database-pool").up()
            .withData("active", active)
            .withData("max", max)
            .build()
        : HealthCheckResponse.named("database-pool").down()
            .withData("pending", pending)
            .withData("active", active)
            .build();
  }
}

This contributes to /health/ready. Pool exhaustion will cause a readiness failure and trigger your Vigilmon readiness alert.


Step 6: Monitor JWT Authentication Health

Helidon MP supports MicroProfile JWT Auth. JWT validation failures — caused by expired keys, misconfigured JWKS URIs, or clock skew — cause authentication to fail for all users. Add a JWT health check:

@ApplicationScoped
@Liveness
public class JwtHealthCheck implements HealthCheck {

  @Inject
  private JwtAuthProvider jwtProvider;

  @Override
  public HealthCheckResponse call() {
    try {
      // Verify JWKS endpoint is reachable and key set is non-empty
      boolean keysLoaded = jwtProvider.getKeyCount() > 0;
      return keysLoaded
          ? HealthCheckResponse.up("jwt-auth")
          : HealthCheckResponse.down("jwt-auth").withData("reason", "no keys loaded").build();
    } catch (Exception e) {
      return HealthCheckResponse.down("jwt-auth").withData("error", e.getMessage()).build();
    }
  }
}

Step 7: Monitor GraalVM Native Image Startup (Optional)

If you compile Helidon to a GraalVM native executable, startup time regressions can indicate native image build issues or missing AOT metadata. Add a startup time check using a Vigilmon Heartbeat with a narrow timeout:

#!/bin/bash
# Wrap your native binary startup in a timing check
START=$(date +%s%3N)
./helidon-app &
APP_PID=$!

# Wait for readiness
until curl -fsS http://localhost:8080/health/ready > /dev/null 2>&1; do
  sleep 0.1
done

END=$(date +%s%3N)
STARTUP_MS=$(( END - START ))

# Alert if startup exceeds 500ms (adjust to your baseline)
if [ "$STARTUP_MS" -lt 500 ]; then
  curl -fsS https://vigilmon.online/heartbeat/YOUR_STARTUP_HEARTBEAT_ID
fi

echo "Startup: ${STARTUP_MS}ms"

Create a Vigilmon Heartbeat monitor with a 10-minute timeout and integrate this check into your deployment pipeline.


Step 8: Monitor JVM Heap and GC Pause Health

When running on the JVM (rather than native), GC pauses can cause request latency spikes. Push a heartbeat from a background thread that monitors heap usage and GC pause duration:

@ApplicationScoped
@Startup
public class JvmHealthReporter {

  @Inject
  private VigilmonHeartbeat heartbeat;

  @Scheduled(fixedDelay = 60000)
  public void reportJvmHealth() {
    MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
    long heapUsed = mem.getHeapMemoryUsage().getUsed();
    long heapMax = mem.getHeapMemoryUsage().getMax();
    double heapPct = (double) heapUsed / heapMax * 100;

    long maxGcPause = ManagementFactory.getGarbageCollectorMXBeans().stream()
        .mapToLong(gc -> gc.getCollectionTime() / Math.max(gc.getCollectionCount(), 1))
        .max().orElse(0);

    if (heapPct < 85 && maxGcPause < 500) {
      heartbeat.fire("YOUR_JVM_HEARTBEAT_ID");
    }
  }
}

Create a Vigilmon Heartbeat monitor with a 3-minute timeout. A heap spike above 85% or GC pause above 500ms will stop the heartbeat and trigger an alert.


Alerting Configuration

Configure escalation paths for each Helidon monitoring signal:

| Alert | Condition | Recommended Channel | |-------|-----------|---------------------| | Liveness probe failure | HTTP 503 on /health/live | PagerDuty / SMS | | Readiness probe failure | HTTP 503 on /health/ready | Slack | | Metrics endpoint down | Keyword check fails | Email | | Latency SLA breach | Liveness returns DOWN due to p99 | Slack | | Circuit breaker open | Liveness returns DOWN | Slack | | DB pool exhaustion | Readiness returns DOWN | PagerDuty | | JWT key loss | Liveness returns DOWN | PagerDuty | | Native startup regression | Heartbeat missing | Email | | JVM heap/GC alert | Heartbeat missing > 3 min | Slack |

In Vigilmon, go to Alerts → Notification Channels to add your Slack webhook, PagerDuty key, or email address.


Conclusion

Helidon's built-in MicroProfile Health and Metrics endpoints give you monitoring hooks at no instrumentation cost — Vigilmon connects directly to /health/live and /health/ready to get immediate alerting on liveness failures, readiness degradation, and latency SLA breaches. By pairing those built-in endpoints with a few custom health indicators for circuit breakers, connection pools, and JVM state, you get complete observability coverage of your Helidon microservices.

Start with a free Vigilmon account and wire up your first Helidon health monitor in under two minutes.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →