Fix duplicate connection verification logs: add debounce and state-ch… (#413)

* Fix duplicate connection verification logs: add debounce and state-change-only logging

* Address CodeRabbit feedback: use status constants, fix comments, remove redundant code
main
dsarno 2025-12-01 20:12:39 -08:00 committed by GitHub
parent b57a2ece9d
commit 50f612cbf2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 67 additions and 9 deletions

View File

@ -44,6 +44,14 @@ namespace MCPForUnity.Editor.Windows.Components.Connection
private Button testConnectionButton; private Button testConnectionButton;
private bool connectionToggleInProgress; private bool connectionToggleInProgress;
private Task verificationTask;
private string lastHealthStatus;
// Health status constants
private const string HealthStatusUnknown = "Unknown";
private const string HealthStatusHealthy = "Healthy";
private const string HealthStatusPingFailed = "Ping Failed";
private const string HealthStatusUnhealthy = "Unhealthy";
// Events // Events
public event Action OnManualConfigUpdateRequested; public event Action OnManualConfigUpdateRequested;
@ -173,7 +181,7 @@ namespace MCPForUnity.Editor.Windows.Components.Connection
statusIndicator.AddToClassList("disconnected"); statusIndicator.AddToClassList("disconnected");
connectionToggleButton.text = "Start Session"; connectionToggleButton.text = "Start Session";
healthStatusLabel.text = "Unknown"; healthStatusLabel.text = HealthStatusUnknown;
healthIndicator.RemoveFromClassList("healthy"); healthIndicator.RemoveFromClassList("healthy");
healthIndicator.RemoveFromClassList("warning"); healthIndicator.RemoveFromClassList("warning");
healthIndicator.AddToClassList("unknown"); healthIndicator.AddToClassList("unknown");
@ -408,15 +416,33 @@ namespace MCPForUnity.Editor.Windows.Components.Connection
} }
public async Task VerifyBridgeConnectionAsync() public async Task VerifyBridgeConnectionAsync()
{
// Prevent concurrent verification calls
if (verificationTask != null && !verificationTask.IsCompleted)
{
return;
}
verificationTask = VerifyBridgeConnectionInternalAsync();
await verificationTask;
}
private async Task VerifyBridgeConnectionInternalAsync()
{ {
var bridgeService = MCPServiceLocator.Bridge; var bridgeService = MCPServiceLocator.Bridge;
if (!bridgeService.IsRunning) if (!bridgeService.IsRunning)
{ {
healthStatusLabel.text = "Disconnected"; healthStatusLabel.text = HealthStatusUnknown;
healthIndicator.RemoveFromClassList("healthy"); healthIndicator.RemoveFromClassList("healthy");
healthIndicator.RemoveFromClassList("warning"); healthIndicator.RemoveFromClassList("warning");
healthIndicator.AddToClassList("unknown"); healthIndicator.AddToClassList("unknown");
// Only log if state changed
if (lastHealthStatus != HealthStatusUnknown)
{
McpLog.Warn("Cannot verify connection: Bridge is not running"); McpLog.Warn("Cannot verify connection: Bridge is not running");
lastHealthStatus = HealthStatusUnknown;
}
return; return;
} }
@ -426,23 +452,45 @@ namespace MCPForUnity.Editor.Windows.Components.Connection
healthIndicator.RemoveFromClassList("warning"); healthIndicator.RemoveFromClassList("warning");
healthIndicator.RemoveFromClassList("unknown"); healthIndicator.RemoveFromClassList("unknown");
string newStatus;
if (result.Success && result.PingSucceeded) if (result.Success && result.PingSucceeded)
{ {
healthStatusLabel.text = "Healthy"; newStatus = HealthStatusHealthy;
healthStatusLabel.text = newStatus;
healthIndicator.AddToClassList("healthy"); healthIndicator.AddToClassList("healthy");
// Only log if state changed
if (lastHealthStatus != newStatus)
{
McpLog.Debug($"Connection verification successful: {result.Message}"); McpLog.Debug($"Connection verification successful: {result.Message}");
lastHealthStatus = newStatus;
}
} }
else if (result.HandshakeValid) else if (result.HandshakeValid)
{ {
healthStatusLabel.text = "Ping Failed"; newStatus = HealthStatusPingFailed;
healthStatusLabel.text = newStatus;
healthIndicator.AddToClassList("warning"); healthIndicator.AddToClassList("warning");
// Log once per distinct warning state
if (lastHealthStatus != newStatus)
{
McpLog.Warn($"Connection verification warning: {result.Message}"); McpLog.Warn($"Connection verification warning: {result.Message}");
lastHealthStatus = newStatus;
}
} }
else else
{ {
healthStatusLabel.text = "Unhealthy"; newStatus = HealthStatusUnhealthy;
healthStatusLabel.text = newStatus;
healthIndicator.AddToClassList("warning"); healthIndicator.AddToClassList("warning");
// Log once per distinct error state
if (lastHealthStatus != newStatus)
{
McpLog.Error($"Connection verification failed: {result.Message}"); McpLog.Error($"Connection verification failed: {result.Message}");
lastHealthStatus = newStatus;
}
} }
} }
} }

View File

@ -21,6 +21,8 @@ namespace MCPForUnity.Editor.Windows
private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new(); private static readonly HashSet<MCPForUnityEditorWindow> OpenWindows = new();
private bool guiCreated = false; private bool guiCreated = false;
private double lastRefreshTime = 0;
private const double RefreshDebounceSeconds = 0.5;
public static void ShowWindow() public static void ShowWindow()
{ {
@ -181,6 +183,14 @@ namespace MCPForUnity.Editor.Windows
private void RefreshAllData() private void RefreshAllData()
{ {
// Debounce rapid successive calls (e.g., from OnFocus being called multiple times)
double currentTime = EditorApplication.timeSinceStartup;
if (currentTime - lastRefreshTime < RefreshDebounceSeconds)
{
return;
}
lastRefreshTime = currentTime;
connectionSection?.UpdateConnectionStatus(); connectionSection?.UpdateConnectionStatus();
if (MCPServiceLocator.Bridge.IsRunning) if (MCPServiceLocator.Bridge.IsRunning)