This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new fe944a072f Improve cloud membership robustness
fe944a072f is described below

commit fe944a072f25a69b67f47afccd06bb305548d33d
Author: remm <[email protected]>
AuthorDate: Tue Sep 1 16:51:17 2026 +0200

    Improve cloud membership robustness
    
    Any transient error would immediately evict all members, which is
    probably a bit too much.
---
 .../membership/cloud/CloudMembershipProvider.java  |  5 ++++-
 .../membership/cloud/DNSMembershipProvider.java    |  1 +
 .../cloud/KubernetesMembershipProvider.java        | 24 ++++++++++++++++------
 webapps/docs/changelog.xml                         |  4 ++++
 4 files changed, 27 insertions(+), 7 deletions(-)

diff --git 
a/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java 
b/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
index ee61f4f8c9..9012eafd62 100644
--- 
a/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
+++ 
b/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
@@ -195,6 +195,9 @@ public abstract class CloudMembershipProvider extends 
MembershipProviderBase imp
     @Override
     public void heartbeat() {
         Member[] announcedMembers = fetchMembers();
+        if (announcedMembers == null) {
+            return;
+        }
         // Add new members or refresh the members in the membership
         for (Member member : announcedMembers) {
             updateMember(member, true);
@@ -209,7 +212,7 @@ public abstract class CloudMembershipProvider extends 
MembershipProviderBase imp
     /**
      * Fetch current cluster members from the cloud orchestration.
      *
-     * @return the member array
+     * @return the member array, or {@null} if an error occurred
      */
     protected abstract Member[] fetchMembers();
 
diff --git 
a/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java 
b/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java
index e43d66b3b2..46ed70df74 100644
--- 
a/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java
+++ 
b/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java
@@ -164,6 +164,7 @@ public class DNSMembershipProvider extends 
CloudMembershipProvider {
             inetAddresses = InetAddress.getAllByName(dnsServiceName);
         } catch (UnknownHostException exception) {
             log.warn(sm.getString("dnsMembershipProvider.dnsError", 
dnsServiceName), exception);
+            return null;
         }
 
         if (inetAddresses != null) {
diff --git 
a/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
 
b/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
index 410b103fbb..0e3dce2958 100644
--- 
a/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
+++ 
b/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
@@ -28,6 +28,7 @@ import java.nio.file.Path;
 import java.nio.file.attribute.FileTime;
 import java.time.Duration;
 import java.time.Instant;
+import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -155,7 +156,7 @@ public class KubernetesMembershipProvider extends 
CloudMembershipProvider {
     @Override
     protected Member[] fetchMembers() {
         if (streamProvider == null) {
-            return new Member[0];
+            return null;
         }
 
         reloadSaTokenIfChanged();
@@ -164,9 +165,12 @@ public class KubernetesMembershipProvider extends 
CloudMembershipProvider {
 
         try (InputStream stream = streamProvider.openStream(url, headers, 
connectionTimeout, readTimeout);
                 InputStreamReader reader = new InputStreamReader(stream, 
"UTF-8")) {
-            parsePods(reader, members);
+            if (!parsePods(reader, members)) {
+                return null;
+            }
         } catch (IOException ioe) {
             
log.error(sm.getString("kubernetesMembershipProvider.streamError"), ioe);
+            return null;
         }
 
         return members.toArray(new Member[0]);
@@ -202,16 +206,17 @@ public class KubernetesMembershipProvider extends 
CloudMembershipProvider {
      *
      * @param reader The reader with pod data
      * @param members The list to populate with members
+     * @return {@code true} if no error occurred
      */
     @SuppressWarnings("unchecked")
-    protected void parsePods(Reader reader, List<MemberImpl> members) {
+    protected boolean parsePods(Reader reader, List<MemberImpl> members) {
         JSONParser parser = new JSONParser(reader);
         try {
             LinkedHashMap<String,Object> json = parser.object();
             Object itemsObject = json.get("items");
             if (!(itemsObject instanceof List<?>)) {
                 
log.error(sm.getString("kubernetesMembershipProvider.invalidPodsList", "no 
items"));
-                return;
+                return false;
             }
             List<Object> items = (List<Object>) itemsObject;
             for (Object podObject : items) {
@@ -273,8 +278,13 @@ public class KubernetesMembershipProvider extends 
CloudMembershipProvider {
                     continue;
                 }
 
-                long aliveTime =
-                        
Duration.between(Instant.parse(creationTimestampObject.toString()), 
startTime).toMillis();
+                long aliveTime;
+                try {
+                    aliveTime = 
Duration.between(Instant.parse(creationTimestampObject.toString()), 
startTime).toMillis();
+                } catch (DateTimeParseException e) {
+                    
log.warn(sm.getString("kubernetesMembershipProvider.invalidPod", 
"creationTimestamp"), e);
+                    continue;
+                }
 
                 MemberImpl member;
                 try {
@@ -291,6 +301,8 @@ public class KubernetesMembershipProvider extends 
CloudMembershipProvider {
             }
         } catch (Exception e) {
             log.error(sm.getString("kubernetesMembershipProvider.jsonError"), 
e);
+            return false;
         }
+        return true;
     }
 }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index c987996a9c..6746bd781e 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -224,6 +224,10 @@
         <code>NegativeArraySizeException</code> during session state transfer.
         Pull request <pr>1042</pr> provided by lihongyi87. (markt)
       </fix>
+      <fix>
+        Improve robustness of cloud membership providers if an error occurs
+        fetching members. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="WebSocket">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to