From def1b0fb0389270b5f88a416e50da627665731eb Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Tue, 17 Mar 2026 17:21:42 -0700 Subject: [PATCH] Fix heartbeat: check leader != current master before redirect, process duplicated UUIDs first Match Go's volume_grpc_client_to_master.go behavior: 1. Only trigger leader redirect when the leader address differs from the current master (prevents unnecessary reconnect loops when master confirms its own address). 2. Process duplicated_uuids before leader redirect check, matching Go's ordering where duplicate UUID detection takes priority. --- seaweed-volume/src/server/heartbeat.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/seaweed-volume/src/server/heartbeat.rs b/seaweed-volume/src/server/heartbeat.rs index 16dd9d655..502304d3e 100644 --- a/seaweed-volume/src/server/heartbeat.rs +++ b/seaweed-volume/src/server/heartbeat.rs @@ -89,7 +89,7 @@ pub async fn run_heartbeat_with_state( SleepDuplicate(Duration), SleepPulse, } - let action = match do_heartbeat(&config, &state, &grpc_addr, pulse, &mut shutdown_rx) + let action = match do_heartbeat(&config, &state, &grpc_addr, &target_addr, pulse, &mut shutdown_rx) .await { Ok(Some(leader)) => { @@ -346,6 +346,7 @@ async fn do_heartbeat( config: &HeartbeatConfig, state: &Arc, grpc_addr: &str, + current_master: &str, pulse: Duration, shutdown_rx: &mut broadcast::Receiver<()>, ) -> Result, Box> { @@ -428,9 +429,8 @@ async fn do_heartbeat( if metrics_changed { state.metrics_notify.notify_waiters(); } - if !hb_resp.leader.is_empty() { - return Ok(Some(hb_resp.leader)); - } + // Match Go ordering: check duplicated_uuids BEFORE leader redirect. + // Go processes DuplicatedUuids first, then volume options, then leader. if !hb_resp.duplicated_uuids.is_empty() { let duplicate_dirs = { let store = state.store.read().unwrap(); @@ -446,6 +446,11 @@ async fn do_heartbeat( ) .into()); } + // Match Go: only redirect if leader is non-empty AND + // different from the current master we're connected to. + if !hb_resp.leader.is_empty() && current_master != hb_resp.leader { + return Ok(Some(hb_resp.leader)); + } } Ok(None) => return Ok(None), Err(e) => return Err(Box::new(e)),