Skip to content

Commit 2ff7bba

Browse files
committed
Improve the quality of the health check
The valve will check if its associated container and all its children are available. Will return down if any is not available.
1 parent ef5149c commit 2ff7bba

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

java/org/apache/catalina/valves/HealthCheckValve.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919
import java.io.IOException;
2020

2121
import jakarta.servlet.ServletException;
22+
import jakarta.servlet.http.HttpServletResponse;
2223

24+
import org.apache.catalina.Container;
2325
import org.apache.catalina.Context;
2426
import org.apache.catalina.LifecycleException;
2527
import org.apache.catalina.connector.Request;
2628
import org.apache.catalina.connector.Response;
29+
import org.apache.catalina.util.LifecycleBase;
2730
import org.apache.tomcat.util.buf.MessageBytes;
2831

2932

@@ -38,13 +41,24 @@ public class HealthCheckValve extends ValveBase {
3841
" \"checks\": []\n" +
3942
"}";
4043

44+
private static final String DOWN =
45+
"{\n" +
46+
" \"status\": \"DOWN\",\n" +
47+
" \"checks\": []\n" +
48+
"}";
49+
4150
private String path = "/health";
4251

4352
/**
4453
* Will be set to true if the valve is associated with a context.
4554
*/
4655
protected boolean context = false;
4756

57+
/**
58+
* Check if all child containers are available.
59+
*/
60+
protected boolean checkContainersAvailable = true;
61+
4862
public HealthCheckValve() {
4963
super(true);
5064
}
@@ -57,6 +71,14 @@ public final void setPath(String path) {
5771
this.path = path;
5872
}
5973

74+
public boolean getCheckContainersAvailable() {
75+
return this.checkContainersAvailable;
76+
}
77+
78+
public void setCheckContainersAvailable(boolean checkContainersAvailable) {
79+
this.checkContainersAvailable = checkContainersAvailable;
80+
}
81+
6082
@Override
6183
protected synchronized void startInternal() throws LifecycleException {
6284
super.startInternal();
@@ -74,9 +96,28 @@ public void invoke(Request request, Response response)
7496
context ? request.getRequestPathMB() : request.getDecodedRequestURIMB();
7597
if (urlMB.equals(path)) {
7698
response.setContentType("application/json");
77-
response.getOutputStream().print(UP);
99+
if (isAvailable(getContainer())) {
100+
response.getOutputStream().print(UP);
101+
} else {
102+
response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
103+
response.getOutputStream().print(DOWN);
104+
}
78105
} else {
79106
getNext().invoke(request, response);
80107
}
81108
}
109+
110+
protected boolean isAvailable(Container container) {
111+
for (Container child : container.findChildren()) {
112+
if (!isAvailable(child)) {
113+
return false;
114+
}
115+
}
116+
if (container instanceof LifecycleBase) {
117+
return ((LifecycleBase) container).getState().isAvailable();
118+
} else {
119+
return true;
120+
}
121+
}
122+
82123
}

webapps/docs/changelog.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@
4545
issues do not "pop up" wrt. others).
4646
-->
4747
<section name="Tomcat 10.0.0-M9 (markt)" rtext="in development">
48+
<subsection name="Catalina">
49+
<changelog>
50+
<update>
51+
The health check valve will now check the state of its associated
52+
containers to report availability. (remm)
53+
</update>
54+
</changelog>
55+
</subsection>
4856
</section>
4957
<section name="Tomcat 10.0.0-M8 (markt)" rtext="release in progress">
5058
<subsection name="Catalina">

webapps/docs/config/valve.xml

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2236,10 +2236,7 @@
22362236
<subsection name="Introduction">
22372237

22382238
<p>The <strong>Health Check Valve</strong> responds to
2239-
cloud orchestrators health checks. Note that it checks
2240-
that a context is mapped (so that an application is deployed),
2241-
for example if you don't have a ROOT context but demo-1.0
2242-
you have to check for <code>/demo-1.0/health</code></p>
2239+
cloud orchestrators health checks.</p>
22432240
</subsection>
22442241

22452242
<subsection name="Attributes">
@@ -2255,10 +2252,18 @@
22552252
</attribute>
22562253

22572254
<attribute name="path" required="false">
2258-
<p>Path by the cloud orchestrators health check logic.
2255+
<p>Path by the cloud orchestrators health check logic. If the valve
2256+
is associated with a context, then this will be relative to the context
2257+
path. Otherwise, the valve will match the full URI.
22592258
The default value is <strong>/health</strong>.</p>
22602259
</attribute>
22612260

2261+
<attribute name="checkContainersAvailable" required="false">
2262+
<p>If <code>true</code> the valve will check if its associated
2263+
container and all its children are available.
2264+
The default value is <strong>true</strong>.</p>
2265+
</attribute>
2266+
22622267
</attributes>
22632268

22642269
</subsection>

0 commit comments

Comments
 (0)