Skip to content

Commit 045e609

Browse files
authored
Add support for Health 4.0 (helidon-io#3707)
1 parent bd6ea9b commit 045e609

21 files changed

Lines changed: 573 additions & 282 deletions

File tree

docs/mp/guides/04_health.adoc

Lines changed: 145 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
1919
= Helidon MP Health Check Guide
2020
:h1Prefix: MP
21-
:description: Helidon health-checks
22-
:keywords: helidon, health-checks, health, check
21+
:description: Helidon health checks
22+
:keywords: helidon, health checks, health, check
2323
:common-page-prefix-inc: ../../shared/common_prereqs/common_prereqs.adoc
2424
2525
This guide describes how to create a sample MicroProfile (MP) project
@@ -77,17 +77,14 @@ curl http://localhost:8080/health
7777
.JSON response:
7878
----
7979
{
80-
"outcome": "UP",
8180
"status": "UP",
8281
"checks": [
8382
{
8483
"name": "deadlock",
85-
"state": "UP",
8684
"status": "UP"
8785
},
8886
{
8987
"name": "diskSpace",
90-
"state": "UP",
9188
"status": "UP",
9289
"data": {
9390
"free": "325.54 GB",
@@ -99,7 +96,6 @@ curl http://localhost:8080/health
9996
},
10097
{
10198
"name": "heapMemory",
102-
"state": "UP",
10399
"status": "UP",
104100
"data": {
105101
"free": "230.87 MB",
@@ -115,10 +111,6 @@ curl http://localhost:8080/health
115111
}
116112
----
117113
118-
NOTE: In MicroProfile Health 2.0 `outcome` and `state` were replaced by `status` in the JSON response wire format.
119-
Helidon currently provides both fields for backwards compatibility, but use of `outcome` and `state` is deprecated
120-
and will be removed in a future release. You should rely on `status` instead.
121-
122114
=== Custom Liveness Health Checks
123115
124116
You can create application-specific custom health checks and integrate them with Helidon
@@ -162,12 +154,10 @@ curl http://localhost:8080/health/live
162154
.JSON response:
163155
----
164156
{
165-
"outcome": "UP",
166157
"status": "UP",
167158
"checks": [
168159
{
169160
"name": "LivenessCheck",
170-
"state": "UP",
171161
"status": "UP",
172162
"data": {
173163
"time": 1566338255331
@@ -177,7 +167,7 @@ curl http://localhost:8080/health/live
177167
}
178168
----
179169
180-
=== Custom Readiness Health Check
170+
=== Custom Readiness Health Checks
181171
182172
You can add a readiness check to indicate that the application is ready to be used. In this
183173
example, the server will wait five seconds before it becomes ready.
@@ -201,20 +191,20 @@ import org.eclipse.microprofile.health.Readiness;
201191
@Readiness // <2>
202192
@ApplicationScoped
203193
public class GreetReadinessCheck implements HealthCheck {
204-
private AtomicLong readyTime = new AtomicLong(0);
194+
private final AtomicLong readyTime = new AtomicLong(0);
205195
206196
207197
@Override
208198
public HealthCheckResponse call() {
209199
return HealthCheckResponse.named("ReadinessCheck") // <3>
210-
.state(isReady())
200+
.status(isReady())
211201
.withData("time", readyTime.get())
212202
.build();
213203
}
214204
215205
public void onStartUp(
216206
@Observes @Initialized(ApplicationScoped.class) Object init) {
217-
readyTime = new AtomicLong(System.currentTimeMillis()); // <4>
207+
readyTime.set(System.currentTimeMillis()); // <4>
218208
}
219209
220210
/**
@@ -228,9 +218,9 @@ public class GreetReadinessCheck implements HealthCheck {
228218
}
229219
----
230220
<1> Include additional imports.
231-
<2> Annotation indicating that this is a readiness health-check.
221+
<2> Annotation indicating that this is a readiness health check.
232222
<3> Build the `HealthCheckResponse` with status `UP` after five seconds, else `DOWN`.
233-
<4> Initialize the time at startup.
223+
<4> Record the time at startup.
234224
235225
236226
[source,bash]
@@ -246,12 +236,10 @@ curl -v http://localhost:8080/health/ready
246236
< HTTP/1.1 503 Service Unavailable // <1>
247237
...
248238
{
249-
"outcome": "DOWN",
250239
"status": "DOWN",
251240
"checks": [
252241
{
253242
"name": "ReadinessCheck",
254-
"state": "DOWN",
255243
"status": "DOWN",
256244
"data": {
257245
"time": 1566399775700
@@ -275,12 +263,10 @@ curl -v http://localhost:8080/health/ready
275263
< HTTP/1.1 200 OK // <1>
276264
...
277265
{
278-
"outcome": "UP",
279266
"status": "UP",
280267
"checks": [
281268
{
282269
"name": "ReadinessCheck",
283-
"state": "UP",
284270
"status": "UP",
285271
"data": {
286272
"time": 1566399775700
@@ -291,10 +277,121 @@ curl -v http://localhost:8080/health/ready
291277
----
292278
<1> The HTTP status is `200` indicating that the application is ready.
293279
280+
=== Custom Startup Health Checks
281+
282+
You can add a startup check to indicate whether or not the application has initialized to the point that the other health checks make sense.
283+
In this example, the server will wait eight seconds before it declares itself started.
284+
285+
[source,java]
286+
.Create a new `GreetStartedCheck` class with the following content:
287+
----
288+
289+
package io.helidon.examples.quickstart.mp;
290+
291+
import java.time.Duration; // <1>
292+
import java.util.concurrent.atomic.AtomicLong;
293+
import jakarta.enterprise.context.ApplicationScoped;
294+
295+
import jakarta.enterprise.context.Initialized;
296+
import jakarta.enterprise.event.Observes;
297+
import org.eclipse.microprofile.health.HealthCheck;
298+
import org.eclipse.microprofile.health.HealthCheckResponse;
299+
import org.eclipse.microprofile.health.Started;
300+
301+
@Started // <2>
302+
@ApplicationScoped
303+
public class GreetStartedCheck implements HealthCheck {
304+
private final AtomicLong readyTime = new AtomicLong(0);
305+
306+
307+
@Override
308+
public HealthCheckResponse call() {
309+
return HealthCheckResponse.named("StartedCheck") // <3>
310+
.status(isStarted())
311+
.withData("time", readyTime.get())
312+
.build();
313+
}
314+
315+
public void onStartUp(
316+
@Observes @Initialized(ApplicationScoped.class) Object init) {
317+
readyTime.set(System.currentTimeMillis()); // <4>
318+
}
319+
320+
/**
321+
* Become ready after 5 seconds
322+
*
323+
* @return true if application ready
324+
*/
325+
private boolean isStarted() {
326+
return Duration.ofMillis(System.currentTimeMillis() - readyTime.get()).getSeconds() >= 8;
327+
}
328+
}
329+
----
330+
<1> Include additional imports.
331+
<2> Annotation indicating that this is a startup health check.
332+
<3> Build the `HealthCheckResponse` with status `UP` after eight seconds, else `DOWN`.
333+
<4> Record the time at startup of Helidon; the application will declare itself as started eight seconds later.
334+
335+
336+
[source,bash]
337+
.Build and run the application. Issue the curl command with -v within five seconds and you will see that the application has not yet started:
338+
----
339+
curl -v http://localhost:8080/health/started
340+
----
341+
342+
[source,json]
343+
.HTTP response:
344+
----
345+
...
346+
< HTTP/1.1 503 Service Unavailable // <1>
347+
...
348+
{
349+
"status": "DOWN",
350+
"checks": [
351+
{
352+
"name": "StartedCheck",
353+
"status": "DOWN",
354+
"data": {
355+
"time": 1566399775700
356+
}
357+
}
358+
]
359+
}
360+
----
361+
<1> The HTTP status is `503` since the application has not started.
362+
363+
[source,bash]
364+
.After eight seconds you will see the application has started:
365+
----
366+
curl -v http://localhost:8080/health/started
367+
----
368+
369+
[source,json]
370+
.JSON response:
371+
----
372+
...
373+
< HTTP/1.1 200 OK // <1>
374+
...
375+
{
376+
"status": "UP",
377+
"checks": [
378+
{
379+
"name": "StartedCheck",
380+
"status": "UP",
381+
"data": {
382+
"time": 1566399775700
383+
}
384+
}
385+
]
386+
}
387+
----
388+
<1> The HTTP status is `200` indicating that the application is started.
389+
294390
When using the health check URLs, you can get the following health check data:
295391
296-
* custom liveness only - http://localhost:8080/health/live
297-
* custom readiness only - http://localhost:8080/health/ready
392+
* liveness only - http://localhost:8080/health/live
393+
* readiness only - http://localhost:8080/health/ready
394+
* startup checks only - http://localhost:8080/health/started
298395
* all health check data - http://localhost:8080/health
299396
300397
[source,bash]
@@ -307,20 +404,24 @@ curl http://localhost:8080/health
307404
.JSON response:
308405
----
309406
{
310-
"outcome": "UP",
311407
"status": "UP",
312408
"checks": [
313409
{
314410
"name": "LivenessCheck",
315-
"state": "UP",
316411
"status": "UP",
317412
"data": {
318413
"time": 1566403431536
319414
}
320415
},
321416
{
322417
"name": "ReadinessCheck",
323-
"state": "UP",
418+
"status": "UP",
419+
"data": {
420+
"time": 1566403280639
421+
}
422+
},
423+
{
424+
"name": "StartedCheck",
324425
"status": "UP",
325426
"data": {
326427
"time": 1566403280639
@@ -384,6 +485,7 @@ health:
384485
curl http://localhost:8080/myhealth
385486
curl http://localhost:8080/myhealth/live
386487
curl http://localhost:8080/myhealth/ready
488+
curl http://localhost:8080/myhealth/started
387489
----
388490
389491
The following example will change the root path and the health port.
@@ -414,12 +516,13 @@ health:
414516
curl http://localhost:8081/myhealth
415517
curl http://localhost:8081/myhealth/live
416518
curl http://localhost:8081/myhealth/ready
519+
curl http://localhost:8081/myhealth/started
417520
----
418521
419-
=== Using Liveness and Readiness Health Checks with Kubernetes
522+
=== Using Liveness, Readiness, and Startup Health Checks with Kubernetes
420523
421524
The following example shows how to integrate the Helidon health check API with an application that implements
422-
health endpoints for the Kubernetes liveness and readiness probes.
525+
health endpoints for the Kubernetes liveness, readiness, and startup probes.
423526
424527
*Delete the contents of `application.yaml` so that the default health endpoint path and port are used.*
425528
@@ -486,6 +589,14 @@ spec:
486589
initialDelaySeconds: 5 // <6>
487590
periodSeconds: 2
488591
timeoutSeconds: 3
592+
startupProbe:
593+
httpGet:
594+
path: /health/started // <7>
595+
port: 8080
596+
initialDelaySeconds: 8 // <8>
597+
periodSeconds: 10
598+
timeoutSeconds: 3
599+
failureThreshold: 3
489600
---
490601
----
491602
<1> A service of type `NodePort` that serves the default routes on port `8080`.
@@ -494,6 +605,8 @@ spec:
494605
<4> The liveness probe configuration.
495606
<5> The HTTP endpoint for the readiness probe.
496607
<6> The readiness probe configuration.
608+
<7> The HTTP endpoint for the startup probe.
609+
<8> The startup probe configuration.
497610
498611
499612
[source,bash]
@@ -531,12 +644,12 @@ kubectl delete -f ./health.yaml
531644
This guide demonstrated how to use health checks in a Helidon MP application as follows:
532645
533646
* Access the default health checks
534-
* Create and use custom readiness and liveness checks
647+
* Create and use custom readiness, liveness, and startup checks
535648
* Customize the health check root path and port
536649
* Integrate Helidon health check API with Kubernetes
537650
538651
Refer to the following references for additional information:
539652
540-
* MicroProfile health-check specification at https://github.com/eclipse/microprofile-health/releases/tag/2.0
541-
* MicroProfile health-check Javadoc at https://javadoc.io/doc/org.eclipse.microprofile.health/microprofile-health-api/2.0
653+
* MicroProfile health check specification at https://github.com/eclipse/microprofile-health/releases/tag/2.0
654+
* MicroProfile health check Javadoc at https://javadoc.io/doc/org.eclipse.microprofile.health/microprofile-health-api/2.0
542655
* Helidon Javadoc at https://helidon.io/docs/latest/apidocs/index.html?overview-summary.html

0 commit comments

Comments
 (0)