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

apupier pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new e6f046f0254f CAMEL-25488: camel-jgroups-raft - tests log the election 
and report more about the nodes when no leader is elected
e6f046f0254f is described below

commit e6f046f0254f297dec42e514d5020df0f6646ccf
Author: AurĂ©lien Pupier <[email protected]>
AuthorDate: Wed Oct 28 12:49:07 2026 +0100

    CAMEL-25488: camel-jgroups-raft - tests log the election and report more
    about the nodes when no leader is elected
    
    On the failures seen in CI, the nodes A and B agree on the leader A at
    term 2 while the node C
    has no leader and a term that keeps increasing (7, 58, 109, 193), so the
    node C does not accept
    the leader. Log the election (ELECTION, RAFT, GMS and MERGE3) of the
    channels created by the tests,
    and report the role, the vote and whether the voting thread is running
    for each node, to find out
    how the node C ends up in this state.
    
    Co-authored-by: IBM Bob 2.2.1
    Signed-off-by: AurĂ©lien Pupier <[email protected]>
---
 .../jgroups/raft/JGroupsRaftAbstractTest.java      |  3 +++
 .../component/jgroups/raft/RaftNodesState.java     | 28 ++++++++++++++++++++++
 .../cluster/JGroupsRaftClusterAbstractTest.java    |  4 +++-
 3 files changed, 34 insertions(+), 1 deletion(-)

diff --git 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/JGroupsRaftAbstractTest.java
 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/JGroupsRaftAbstractTest.java
index 6792f939ae0b..27150ab6d8de 100644
--- 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/JGroupsRaftAbstractTest.java
+++ 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/JGroupsRaftAbstractTest.java
@@ -44,6 +44,9 @@ public abstract class JGroupsRaftAbstractTest extends 
CamelTestSupport {
      * address to forward to.
      */
     protected void waitForLeader(int attempts, RaftHandle... handles) {
+        for (RaftHandle rh : handles) {
+            RaftNodesState.enableElectionLogging(rh.channel());
+        }
         try {
             await().atMost(attempts, TimeUnit.SECONDS)
                     .pollInterval(500, TimeUnit.MILLISECONDS)
diff --git 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/RaftNodesState.java
 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/RaftNodesState.java
index 8cfb5ec8e3b7..95305ba679fd 100644
--- 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/RaftNodesState.java
+++ 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/RaftNodesState.java
@@ -17,13 +17,37 @@
 package org.apache.camel.component.jgroups.raft;
 
 import org.jgroups.JChannel;
+import org.jgroups.protocols.MERGE3;
+import org.jgroups.protocols.pbcast.GMS;
+import org.jgroups.protocols.raft.RAFT;
+import org.jgroups.protocols.raft.election.BaseElection;
 import org.jgroups.raft.RaftHandle;
+import org.jgroups.stack.Protocol;
+import org.jgroups.stack.ProtocolStack;
 
 public final class RaftNodesState {
 
     private RaftNodesState() {
     }
 
+    /**
+     * Raise the log level of the protocols involved in the election of the 
leader, to find out how it goes when it
+     * stalls. The logs of JGroups go to the console, and the output of a test 
is small when it succeeds.
+     */
+    public static void enableElectionLogging(JChannel channel) {
+        ProtocolStack stack = channel.getProtocolStack();
+        setLevel(stack.findProtocol(BaseElection.class), "trace");
+        setLevel(stack.findProtocol(RAFT.class), "debug");
+        setLevel(stack.findProtocol(GMS.class), "debug");
+        setLevel(stack.findProtocol(MERGE3.class), "debug");
+    }
+
+    private static void setLevel(Protocol protocol, String level) {
+        if (protocol != null) {
+            protocol.setLevel(level);
+        }
+    }
+
     /**
      * Describe the state of the given nodes, to find out why no leader has 
been elected.
      */
@@ -31,12 +55,16 @@ public final class RaftNodesState {
         StringBuilder sb = new StringBuilder("State of the nodes when giving 
up waiting for a leader:");
         for (RaftHandle rh : handles) {
             JChannel channel = rh.channel();
+            BaseElection election = 
channel.getProtocolStack().findProtocol(BaseElection.class);
             sb.append(System.lineSeparator())
                     .append("  raftId=").append(rh.raftId())
+                    .append(" role=").append(rh.raft().role())
                     .append(" connected=").append(channel.isConnected())
                     .append(" isLeader=").append(rh.isLeader())
                     .append(" leader=").append(rh.leader())
                     .append(" term=").append(rh.currentTerm())
+                    .append(" votedFor=").append(rh.raft().votedFor())
+                    .append(" votingThreadRunning=").append(election != null 
&& election.isVotingThreadRunning())
                     .append(" view=").append(channel.getView());
         }
         return sb.toString();
diff --git 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/cluster/JGroupsRaftClusterAbstractTest.java
 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/cluster/JGroupsRaftClusterAbstractTest.java
index e77ef2799ae3..efee49589234 100644
--- 
a/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/cluster/JGroupsRaftClusterAbstractTest.java
+++ 
b/components/camel-jgroups-raft/src/test/java/org/apache/camel/component/jgroups/raft/cluster/JGroupsRaftClusterAbstractTest.java
@@ -65,7 +65,9 @@ public abstract class JGroupsRaftClusterAbstractTest {
      * Create the Raft handle of a node and keep track of it, so that its 
channel is closed at the end of the test.
      */
     protected RaftHandle createHandle(String id, StateMachine stateMachine) 
throws Exception {
-        RaftHandle handle = new RaftHandle(new 
JChannel("raftABC.xml").name(id), stateMachine).raftId(id);
+        JChannel channel = new JChannel("raftABC.xml").name(id);
+        RaftNodesState.enableElectionLogging(channel);
+        RaftHandle handle = new RaftHandle(channel, stateMachine).raftId(id);
         openHandles.add(handle);
         return handle;
     }

Reply via email to