yuqi1129 commented on code in PR #13067:
URL: https://github.com/apache/gravitino/pull/13067#discussion_r3978516428


##########
docs/gravitino-server-config.md:
##########
@@ -208,19 +208,20 @@ Gravitino exposes three health endpoints following
 of them are exempt from authentication, so Kubernetes probes, load balancers, 
and traffic managers
 reach them without credentials.
 
-| Endpoint                | Root Alias          | Description                  
                                                                                
                               | HTTP Status |
-|-------------------------|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------|-------------|
-| `GET /api/health/live`  | `GET /health/live`  | Liveness. Returns 200 as 
long as an HTTP server thread can respond. Use it to decide whether to restart 
a pod.                              | 200         |
-| `GET /api/health/ready` | `GET /health/ready` | Readiness. Returns 200 when 
the entity store answers within the probe timeout, 503 when it is unavailable 
or slow. Use it to route traffic. | 200 or 503  |
-| `GET /api/health`       | `GET /health`       | Aggregate. Returns 200 when 
both of the above pass. Also aliased as `GET /health.html`.                     
                                | 200 or 503  |
+| Endpoint                | Root Alias          | Description                  
                                                                                
                                       | HTTP Status |
+|-------------------------|---------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|-------------|
+| `GET /api/health/live`  | `GET /health/live`  | Liveness. Returns 200 if an 
HTTP thread can respond and no OOM has been observed; otherwise 503. Use it to 
decide whether to restart a pod.         | 200 or 503  |
+| `GET /api/health/ready` | `GET /health/ready` | Readiness. Returns 200 when 
no OOM has been observed and the entity store answers within the probe timeout; 
otherwise 503. Use it to route traffic. | 200 or 503  |
+| `GET /api/health`       | `GET /health`       | Aggregate. Returns 200 when 
both of the above pass. Also aliased as `GET /health.html`.                     
                                        | 200 or 503  |
 
 | Configuration Item                                   | Description           
                                              | Default Value |
 
|------------------------------------------------------|---------------------------------------------------------------------|---------------|
 | `gravitino.server.health.entityStore.probeTimeoutMs` | Timeout in 
milliseconds for the entity store probe behind `/ready`. | `2000`        |
 
 Every endpoint returns the same JSON shape, but not the same checks. `code` is 
always `0`,
 `status` is `UP` or `DOWN`, and `checks` carries one entry per component 
probed. `/live` reports
-`httpServer` alone, `/ready` reports `entityStore` alone, and the aggregate 
endpoint reports both:
+`httpServer` alone, `/ready` reports `entityStore` alone, and the aggregate 
endpoint reports both
+while no OOM has been observed:

Review Comment:
   Fixed in 1762ae3. The main-server status description, JSON example, and 
`jvm: down` text now use lowercase `up`/`down`.



##########
docs/health-and-readiness.md:
##########
@@ -54,7 +57,44 @@ endpoint rather than to a check of its own.
 
 The response body carries an overall status and a list of individual checks. 
Each check has a name,
 a status of UP or DOWN, and a details map that explains a failure. On the 
Gravitino server the two
-check names are `httpServer` and `entityStore`.
+normal check names are `httpServer` and `entityStore`. After an observed 
out-of-memory error, all

Review Comment:
   Fixed in 1762ae3. This section now uses lowercase `up`/`down` for the main 
server, and the OOM section explicitly distinguishes Gravitino/Lance from 
Iceberg REST, which retains uppercase status values.



##########
docs/iceberg-rest-service.md:
##########
@@ -724,7 +724,7 @@ The Iceberg REST server exposes three health check 
endpoints following the same
 
 | Endpoint                    | Description                                    
                                                                            | 
HTTP status |
 
|-----------------------------|----------------------------------------------------------------------------------------------------------------------------|-------------|
-| `GET /iceberg/health/live`  | Liveness probe. Returns 200 as long as the 
HTTP server thread can respond.                                                 
| 200         |
+| `GET /iceberg/health/live`  | Liveness probe. Returns 200 when the HTTP 
thread can respond and no OOM has been observed.                                
 | 200 / 503   |

Review Comment:
   Updated in 1762ae3. The live endpoint description now explicitly says it 
returns 503 after an observed OOM. Readiness also lists the no-OOM condition 
alongside initialization, with 503 otherwise.



##########
server-common/src/main/java/org/apache/gravitino/server/web/JettyServer.java:
##########
@@ -484,6 +484,7 @@ public Thread run() {
                     thread.setName(getName() + "-" + thread.getId());
                     thread.setUncaughtExceptionHandler(
                         (t, throwable) -> {
+                          ServerHealth.getInstance().recordFailure(throwable);

Review Comment:
   Fixed in 1762ae3. `JettyServer` now installs an OOM-recording filter first 
on `/*`; it records escaping failures and rethrows them. Both 
`AuthenticationFilter` catch branches also record before calling 
`sendAuthErrorResponse`, covering wrapped OOM consumed by authentication and 
the Iceberg/Lance response overrides.
   
   Added real HTTP tests for direct/wrapped OOM in downstream filters, 
non-Jersey servlets, and authentication. The filter/servlet tests verify all 
seven main-server health paths return 503 while a warm endpoint still succeeds; 
the authentication tests verify recording precedes response conversion. 
Ordinary failures do not mark the server unhealthy. The docs now describe the 
worker handler as an additional fallback.



##########
server-common/src/main/java/org/apache/gravitino/server/web/ServerHealth.java:
##########
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.gravitino.server.web;
+
+import javax.annotation.Nullable;
+
+/**
+ * Records out-of-memory failures observed by the server. Once recorded, the 
failure remains until
+ * the process restarts; a successful request does not establish that the JVM 
has recovered.
+ *
+ * <p>The failure path only sets a flag. It does not retain the error, format 
its stack trace, or
+ * allocate a collection while walking its causes.
+ */
+public final class ServerHealth {
+  private static final ServerHealth INSTANCE = new ServerHealth();
+
+  private volatile boolean outOfMemory;
+
+  /** Creates an independent health state, initially healthy. */
+  public ServerHealth() {}
+
+  /**
+   * Returns the shared state used by the server's request and health-check 
paths.
+   *
+   * @return the shared health state
+   */
+  public static ServerHealth getInstance() {
+    return INSTANCE;
+  }
+
+  /**
+   * Records an out-of-memory error, including one wrapped in another 
throwable.
+   *
+   * @param failure the observed failure, or null
+   */
+  public void recordFailure(@Nullable Throwable failure) {

Review Comment:
   I chose the documented-limitation option in 1762ae3. The method Javadoc, 
health documentation, and PR description now explicitly say detection follows 
the throwable and cause chain, excluding suppressed exceptions. This preserves 
the current traversal without the defensive array copies from `getSuppressed()`.



##########
docs/health-and-readiness.md:
##########
@@ -54,7 +57,44 @@ endpoint rather than to a check of its own.
 
 The response body carries an overall status and a list of individual checks. 
Each check has a name,
 a status of UP or DOWN, and a details map that explains a failure. On the 
Gravitino server the two
-check names are `httpServer` and `entityStore`.
+normal check names are `httpServer` and `entityStore`. After an observed 
out-of-memory error, all
+three endpoints instead report the `jvm` failure described below.
+
+## Out-of-memory Failures
+
+A Metaspace or heap `OutOfMemoryError` can leave already-loaded endpoints 
responding successfully
+while other operations fail. A successful HTTP response or entity-store lookup 
therefore does not
+prove recovery after OOM.
+
+The Gravitino, Iceberg REST, and Lance REST servers record OOM observed by 
their Jersey exception
+listeners, error mappers, shared request execution/error-response helpers, and 
Jetty worker
+uncaught-exception handlers. The main server also records failures in 
health-probe tasks.
+Wrapped causes are checked too. Once recorded, the affected service’s health 
endpoints and root
+aliases return HTTP 503 with this body (the main server uses the `/api/health` 
prefix):
+
+```json
+{
+  "code": 0,
+  "status": "down",
+  "checks": [
+    {
+      "name": "jvm",
+      "status": "down",
+      "details": { "reason": "OutOfMemoryError; restart required" }
+    }
+  ]
+}
+```
+
+This state lasts until process restart, even if subsequent ordinary API 
requests succeed. Health
+checks skip the entity-store probe once OOM is recorded. A database outage, 
ordinary HTTP 500,
+`StackOverflowError`, or missing connector class alone does not set this state.
+
+Detection covers errors reaching these server boundaries; it cannot detect an 
OOM swallowed
+entirely by a connector or unrelated background executor. This is not a 
JVM-wide OOM trap. If the
+JVM cannot allocate enough memory to answer a probe, the probe may fail 
without a JSON response.
+Each service tracks errors observed within its own runtime. Auxiliary services 
with isolated

Review Comment:
   Corrected in 1762ae3 and the PR description. Embedded services share the 
marker through the default auxiliary classloaders; separate JVM processes track 
OOM independently. The docs still recommend probing each service port because 
HTTP availability and initialization checks remain service-specific.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to