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/liveand/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:
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter:
http://your-helidon-service:8080/health/live. - Set Expected HTTP status to
200. - Set Check interval to
1 minute. - 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:
- Click Add Monitor.
- Set Type to
HTTP / HTTPSwith Keyword check. - Enter:
http://your-helidon-service:8080/metrics. - Set Keyword to
"base"(the base metrics scope is always present in MicroProfile Metrics). - Set Check interval to
2 minutes. - 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.