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

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


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

commit a8c20fc34d17b829063ea37b5e72fee59b5e249b
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    | 47 +++++++++++-----------
 .../cloud/KubernetesMembershipProvider.java        | 24 ++++++++---
 webapps/docs/changelog.xml                         |  4 ++
 4 files changed, 49 insertions(+), 31 deletions(-)

diff --git 
a/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java 
b/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
index 87bf911797..4a2d054367 100644
--- 
a/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
+++ 
b/java/org/apache/catalina/tribes/membership/cloud/CloudMembershipProvider.java
@@ -193,6 +193,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);
@@ -207,7 +210,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 8ac02394be..15d8b0d827 100644
--- 
a/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java
+++ 
b/java/org/apache/catalina/tribes/membership/cloud/DNSMembershipProvider.java
@@ -157,40 +157,39 @@ public class DNSMembershipProvider extends 
CloudMembershipProvider {
 
     @Override
     protected Member[] fetchMembers() {
-        List<MemberImpl> members = new ArrayList<>();
 
         InetAddress[] inetAddresses = null;
         try {
             inetAddresses = InetAddress.getAllByName(dnsServiceName);
         } catch (UnknownHostException exception) {
             log.warn(sm.getString("dnsMembershipProvider.dnsError", 
dnsServiceName), exception);
+            return null;
         }
 
-        if (inetAddresses != null) {
-            for (InetAddress inetAddress : inetAddresses) {
-                String ip = inetAddress.getHostAddress();
-                byte[] id = digest(ip.getBytes(StandardCharsets.US_ASCII));
-                // We found ourselves, ignore
-                if (ip.equals(localIp)) {
-                    // Update the UID on initial lookup
-                    Member localMember = service.getLocalMember(false);
-                    if (localMember.getUniqueId() == 
CloudMembershipService.INITIAL_ID &&
-                            localMember instanceof MemberImpl) {
-                        ((MemberImpl) localMember).setUniqueId(id);
-                    }
-                    continue;
-                }
-                long aliveTime = -1;
-                MemberImpl member;
-                try {
-                    member = new MemberImpl(ip, port, aliveTime);
-                } catch (IOException ioe) {
-                    
log.error(sm.getString("dnsMembershipProvider.memberError"), ioe);
-                    continue;
+        List<MemberImpl> members = new ArrayList<>();
+        for (InetAddress inetAddress : inetAddresses) {
+            String ip = inetAddress.getHostAddress();
+            byte[] id = digest(ip.getBytes(StandardCharsets.US_ASCII));
+            // We found ourselves, ignore
+            if (ip.equals(localIp)) {
+                // Update the UID on initial lookup
+                Member localMember = service.getLocalMember(false);
+                if (localMember.getUniqueId() == 
CloudMembershipService.INITIAL_ID &&
+                        localMember instanceof MemberImpl) {
+                    ((MemberImpl) localMember).setUniqueId(id);
                 }
-                member.setUniqueId(id);
-                members.add(member);
+                continue;
             }
+            long aliveTime = -1;
+            MemberImpl member;
+            try {
+                member = new MemberImpl(ip, port, aliveTime);
+            } catch (IOException ioe) {
+                log.error(sm.getString("dnsMembershipProvider.memberError"), 
ioe);
+                continue;
+            }
+            member.setUniqueId(id);
+            members.add(member);
         }
 
         return members.toArray(new Member[0]);
diff --git 
a/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
 
b/java/org/apache/catalina/tribes/membership/cloud/KubernetesMembershipProvider.java
index e930be8bed..bdac124c59 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, 
StandardCharsets.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 8e7ff746ea..318530f458 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -216,6 +216,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