Polly重试不生效且无日志输出,求代码问题排查指导
Let's break down what's going wrong with both your original code and the Polly implementation, then fix them step by step.
Why the Original Code Causes Lag
Your initial implementation holds the Monitor lock while sleeping in the while loop. Since Thread.Sleep(100) doesn't release the lock, any other thread trying to acquire _syncRoot will be blocked for the entire duration of the wait. This is exactly what's causing your卡顿 (lag).
Why the Polly Version Isn't Working
Your Polly code has three critical issues:
- Incorrect Logging: Your log statement
Log.LogInformation("retry {TimeOut}s");doesn't pass the actual timeout value to the placeholder. It'll just print "retry {TimeOut}s" instead of the real number. - Wrong Callback Signature: For result-based policies (
HandleResult<bool>), the retry callback receives aDelegateResult<bool>(not anException) as the first parameter. Your code uses(ex, time)which is meant for exception-handling policies. - No Actual Connection Attempt: You're executing
() => connection.IsConnectedwhich only checks the current state—you aren't triggering any logic to establish a connection. Ifconnectiondoesn't auto-reconnect in the background, Polly will just keep checkingfalseforever. - Still Holding the Lock During Retries: Just like the original code, you're running the entire Polly retry sequence inside the
Monitorlock. This keeps blocking other threads, so the lag issue remains.
Fixed Implementations
Option 1: Polly for Retrying Connection Attempts (Recommended)
If your connection object has an explicit Connect() method to initiate a connection, use this approach. We'll shrink the lock scope to only protect the initial connection trigger, not the entire wait/retry process:
private bool TryConnect() { // Early exit if already connected if (connection.IsConnected) { return true; } Monitor.Enter(_syncRoot); try { // Double-check to avoid redundant work (another thread might have connected while we waited for the lock) if (connection.IsConnected) { return true; } // Define Polly retry policy: retry on failed connection attempts var retryPolicy = Policy.HandleResult<bool>(result => !result) .WaitAndRetry( retryCount: _retryCount, sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // Exponential backoff onRetry: (result, timeSpan, retryAttempt, context) => { Log.LogInformation("Connection failed. Retrying in {WaitTime:F1}s (attempt {RetryNumber})", timeSpan.TotalSeconds, retryAttempt); }); // Execute the actual connection logic bool isConnected = retryPolicy.Execute(() => { try { connection.Connect(); // Replace with your actual connection method return connection.IsConnected; } catch (Exception ex) { Log.LogError(ex, "Connection attempt threw an exception"); return false; } }); return isConnected; } finally { Monitor.Exit(_syncRoot); } }
Option 2: Waiting for Auto-Reconnecting Connection
If your connection automatically tries to reconnect in the background (no need to call Connect()), use this approach to wait for the state change outside the lock to avoid blocking other threads:
private async Task<bool> TryConnectAsync() { if (connection.IsConnected) { return true; } // Only lock to ensure we don't trigger redundant init logic (if needed) Monitor.Enter(_syncRoot); try { if (connection.IsConnected) { return true; } // Uncomment if you need to trigger the initial connection attempt // connection.InitiateReconnect(); } finally { Monitor.Exit(_syncRoot); } // Wait for connection outside the lock to avoid blocking other threads int attempt = 0; while (!connection.IsConnected && attempt < _retryCount) { var waitTime = TimeSpan.FromSeconds(Math.Pow(2, attempt)); await Task.Delay(waitTime); Log.LogInformation("Waiting for connection... Attempt {AttemptNumber}", attempt + 1); attempt++; } return connection.IsConnected; }
内容的提问来源于stack exchange,提问作者finn

