loserwang1024 commented on code in PR #3400:
URL: https://github.com/apache/fluss/pull/3400#discussion_r3338499807


##########
fluss-server/src/main/java/org/apache/fluss/server/coordinator/CoordinatorContext.java:
##########
@@ -106,6 +106,13 @@ public class CoordinatorContext {
      */
     private final Map<Integer, Set<TableBucket>> replicasOnOffline = new 
HashMap<>();
 
+    /**
+     * Tracks leader buckets that are currently inactive — a leader is 
inactive from the moment we
+     * send NotifyLeaderAndIsr until the target server responds successfully 
confirming it is the
+     * leader. Also inactive when leader == NO_LEADER.
+     */
+    private final Set<TableBucket> inactiveLeaderBuckets = new HashSet<>();

Review Comment:
   Naming: inactiveLeaderBuckets → pendingLeaderActivationBuckets
   
   The name over-claims. The set is only populated in 
sendNotifyLeaderAndIsrRequest — buckets where we've sent a NotifyLeaderAndIsr 
and await leadership confirmation. Buckets leaderless for other reasons (server 
offline, rebalance with no new leader yet) aren't in it, though their leader is 
effectively inactive. So it really means "leader change dispatched, awaiting 
confirmation" — pendingLeaderActivationBuckets fits. Avoid pendingIsr...: this 
has nothing to do with ISR (that's a separate dimension driving YELLOW).
   
   Bigger issue: "active leader" is defined twice. computeClusterHealth checks 
leader != NO_LEADER && liveServers.contains(leader) && !inSet, but the helper 
only checks the set:
   
   ```java
   public boolean isLeaderActive(TableBucket bucket) {
       return !inactiveLeaderBuckets.contains(bucket); // ignores liveServers / 
NO_LEADER
   }
   ```
   
   So for a leader on a dead server, isLeaderActive() says true while 
computeClusterHealth() says RED — inconsistent, and a trap for future reuse.
   
   Suggestion: rename the set + make isLeaderActive the single source of truth:
   
   ```java
   public boolean isLeaderActive(TableBucket tb) {
       return getBucketLeaderAndIsr(tb)
           .map(lai -> lai.leader() != LeaderAndIsr.NO_LEADER
                   && liveTabletServers.containsKey(lai.leader())
                   && !pendingLeaderActivationBuckets.contains(tb))
           .orElse(false);
   }
   ```
   Then computeClusterHealth just calls ctx.isLeaderActive(tb).



##########
fluss-server/src/main/java/org/apache/fluss/server/coordinator/CoordinatorService.java:
##########
@@ -291,6 +294,62 @@ public CoordinatorService(
         this.coordinatorLeaderElection = coordinatorLeaderElection;
     }
 
+    @Override
+    public CompletableFuture<GetClusterHealthResponse> getClusterHealth(
+            GetClusterHealthRequest request) {
+        AccessContextEvent<GetClusterHealthResponse> event =
+                new 
AccessContextEvent<>(CoordinatorService::computeClusterHealth);
+        eventManagerSupplier.get().put(event);
+        return event.getResultFuture();
+    }
+
+    @VisibleForTesting
+    static GetClusterHealthResponse computeClusterHealth(CoordinatorContext 
ctx) {
+        GetClusterHealthResponse response = new GetClusterHealthResponse();
+
+        int numReplicas = 0;
+        int inSyncReplicas = 0;
+        int numLeaderReplicas = 0;
+        int activeLeaderReplicas = 0;
+        Set<TableBucket> inactiveLeaders = ctx.getInactiveLeaderBuckets();
+
+        for (TableBucket tb : ctx.getAllBuckets()) {
+            List<Integer> assignment = ctx.getAssignment(tb);
+            numReplicas += assignment.size();
+            numLeaderReplicas++;
+
+            Optional<LeaderAndIsr> laiOpt = ctx.getBucketLeaderAndIsr(tb);
+            if (laiOpt.isPresent()) {
+                LeaderAndIsr lai = laiOpt.get();
+                inSyncReplicas += lai.isr().size();
+                if (lai.leader() != LeaderAndIsr.NO_LEADER
+                        && ctx.getLiveTabletServers().containsKey(lai.leader())
+                        && !inactiveLeaders.contains(tb)) {
+                    activeLeaderReplicas++;
+                }
+            }
+        }
+
+        // PbClusterHealthStatus: GREEN=0, YELLOW=1, RED=2, UNKNOWN=3
+        int status;
+        if (numLeaderReplicas == 0) {

Review Comment:
   This can merge with else {
               status = 0; // GREEN
           }



##########
fluss-server/src/main/java/org/apache/fluss/server/RpcServiceBase.java:
##########
@@ -574,6 +576,18 @@ public CompletableFuture<DescribeClusterConfigsResponse> 
describeClusterConfigs(
                 new 
DescribeClusterConfigsResponse().addAllConfigs(toPbConfigEntries(configs)));
     }
 
+    @Override
+    public CompletableFuture<GetClusterHealthResponse> getClusterHealth(

Review Comment:
   Why not move to CoordinatorGateway? Could tablet server support it?



##########
fluss-server/src/main/java/org/apache/fluss/server/coordinator/CoordinatorEventProcessor.java:
##########
@@ -974,10 +975,17 @@ private void 
processNotifyLeaderAndIsrResponseReceivedEvent(
                 offlineReplicas.add(
                         new TableBucketReplica(
                                 
notifyLeaderAndIsrResultForBucket.getTableBucket(), serverId));
+            } else {
+                
succeededBuckets.add(notifyLeaderAndIsrResultForBucket.getTableBucket());
+            }
+        }
+        for (TableBucket tb : succeededBuckets) {
+            Optional<LeaderAndIsr> laiOpt = 
coordinatorContext.getBucketLeaderAndIsr(tb);
+            if (laiOpt.isPresent() && laiOpt.get().leader() == serverId) {
+                coordinatorContext.markLeaderActive(tb);
             }
         }
         if (!offlineReplicas.isEmpty()) {
-            // trigger replicas to offline

Review Comment:
   why remove this comment?



##########
helm/templates/sts-coordinator.yaml:
##########
@@ -122,7 +124,7 @@ spec:
               echo "bind.listeners: ${BIND_LISTENERS}" >> 
$FLUSS_HOME/conf/server.yaml && \
               echo "advertised.listeners: ${ADVERTISED_LISTENERS}" >> 
$FLUSS_HOME/conf/server.yaml && \
 
-              bin/coordinator-server.sh start-foreground
+              exec bin/coordinator-server.sh start-foreground

Review Comment:
   why need to change it?



##########
fluss-server/src/main/java/org/apache/fluss/server/coordinator/CoordinatorRequestBatch.java:
##########
@@ -422,12 +433,20 @@ private void sendNotifyLeaderAndIsrRequest(int 
coordinatorEpoch) {
                                     "Failed to send notify leader and isr 
request to tablet server {}.",
                                     serverId,
                                     throwable);
-                            // todo: in FLUSS-55886145, we will introduce a 
sender thread to send
-                            // the request, and retry if encounter any error; 
It may happens that
-                            // the tablet server is offline and will always 
got error. But,
-                            // coordinator will remove the sender for the 
tablet server and mark all
-                            // replica in the tablet server as offline. so, in 
here, if encounter
-                            // any error, we just ignore it.
+                            // Treat all buckets as failed — clears pending 
state and triggers
+                            // re-election via onReplicaBecomeOffline.
+                            List<NotifyLeaderAndIsrResultForBucket> 
failedResults =
+                                    new ArrayList<>();
+                            ApiError sendError =

Review Comment:
   Currently, after this modification, even a network timeout exception, the 
CoordinatorEventProcessor#processNotifyLeaderAndIsrResponseReceivedEvent will 
mark the server as offlineReplicas 
   
   won't is any problem?
   <img width="1062" height="280" alt="Image" 
src="https://github.com/user-attachments/assets/ecbd5a3a-4568-40ed-8c5d-d8871bd94fd5";
 />



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to