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;
}