This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch 10.1.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/10.1.x by this push:
new 93923ea15c Improve cloud membership robustness
93923ea15c is described below
commit 93923ea15c66d0452ed5d5c3cf81364d0691c5b3
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 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 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 0afb747f28..02a9a4b30f 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -200,6 +200,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]