Reformat/cleanup
All checks were successful
NuGet Package Publish / nuget (push) Successful in 1m10s

This commit is contained in:
Joseph Doherty
2026-02-21 07:53:53 -05:00
parent c6f6d9329a
commit 7ebc2cb567
160 changed files with 7258 additions and 7262 deletions

View File

@@ -1,50 +1,53 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using ZB.MOM.WW.CBDDC.Core.Exceptions;
using ZB.MOM.WW.CBDDC.Core.Network;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using ZB.MOM.WW.CBDDC.Core.Exceptions;
using ZB.MOM.WW.CBDDC.Core.Network;
using TimeoutException = ZB.MOM.WW.CBDDC.Core.Exceptions.TimeoutException;
namespace ZB.MOM.WW.CBDDC.Core.Resilience;
/// <summary>
/// Provides retry logic for transient failures.
/// Provides retry logic for transient failures.
/// </summary>
public class RetryPolicy : IRetryPolicy
{
private readonly IPeerNodeConfigurationProvider _peerNodeConfigurationProvider;
private readonly ILogger<RetryPolicy> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="RetryPolicy"/> class.
/// </summary>
/// <param name="peerNodeConfigurationProvider">The provider for retry configuration values.</param>
/// <param name="logger">The logger instance.</param>
public RetryPolicy(IPeerNodeConfigurationProvider peerNodeConfigurationProvider, ILogger<RetryPolicy>? logger = null)
{
_logger = logger ?? NullLogger<RetryPolicy>.Instance;
_peerNodeConfigurationProvider = peerNodeConfigurationProvider
?? throw new ArgumentNullException(nameof(peerNodeConfigurationProvider));
}
public class RetryPolicy : IRetryPolicy
{
private readonly ILogger<RetryPolicy> _logger;
private readonly IPeerNodeConfigurationProvider _peerNodeConfigurationProvider;
/// <summary>
/// Executes an operation with retry logic.
/// </summary>
/// <typeparam name="T">The result type returned by the operation.</typeparam>
/// <param name="operation">The asynchronous operation to execute.</param>
/// <param name="operationName">The operation name used for logging.</param>
/// <param name="cancellationToken">A token used to cancel retry delays.</param>
public async Task<T> ExecuteAsync<T>(
Func<Task<T>> operation,
string operationName,
CancellationToken cancellationToken = default)
/// <summary>
/// Initializes a new instance of the <see cref="RetryPolicy" /> class.
/// </summary>
/// <param name="peerNodeConfigurationProvider">The provider for retry configuration values.</param>
/// <param name="logger">The logger instance.</param>
public RetryPolicy(IPeerNodeConfigurationProvider peerNodeConfigurationProvider,
ILogger<RetryPolicy>? logger = null)
{
_logger = logger ?? NullLogger<RetryPolicy>.Instance;
_peerNodeConfigurationProvider = peerNodeConfigurationProvider
?? throw new ArgumentNullException(nameof(peerNodeConfigurationProvider));
}
/// <summary>
/// Executes an operation with retry logic.
/// </summary>
/// <typeparam name="T">The result type returned by the operation.</typeparam>
/// <param name="operation">The asynchronous operation to execute.</param>
/// <param name="operationName">The operation name used for logging.</param>
/// <param name="cancellationToken">A token used to cancel retry delays.</param>
public async Task<T> ExecuteAsync<T>(
Func<Task<T>> operation,
string operationName,
CancellationToken cancellationToken = default)
{
var config = await _peerNodeConfigurationProvider.GetConfiguration();
Exception? lastException = null;
for (int attempt = 1; attempt <= config.RetryAttempts; attempt++)
{
for (var attempt = 1; attempt <= config.RetryAttempts; attempt++)
try
{
_logger.LogDebug("Executing {Operation} (attempt {Attempt}/{Max})",
@@ -55,7 +58,7 @@ public class RetryPolicy : IRetryPolicy
catch (Exception ex) when (attempt < config.RetryAttempts && IsTransient(ex))
{
lastException = ex;
var delay = config.RetryDelayMs * attempt; // Exponential backoff
int delay = config.RetryDelayMs * attempt; // Exponential backoff
_logger.LogWarning(ex,
"Operation {Operation} failed (attempt {Attempt}/{Max}). Retrying in {Delay}ms...",
@@ -63,36 +66,31 @@ public class RetryPolicy : IRetryPolicy
await Task.Delay(delay, cancellationToken);
}
}
if (lastException != null)
{
_logger.LogError(lastException,
"Operation {Operation} failed after {Attempts} attempts",
operationName, config.RetryAttempts);
}
else
{
_logger.LogError(
"Operation {Operation} failed after {Attempts} attempts",
operationName, config.RetryAttempts);
}
if (lastException != null)
_logger.LogError(lastException,
"Operation {Operation} failed after {Attempts} attempts",
operationName, config.RetryAttempts);
else
_logger.LogError(
"Operation {Operation} failed after {Attempts} attempts",
operationName, config.RetryAttempts);
throw new CBDDCException("RETRY_EXHAUSTED",
$"Operation '{operationName}' failed after {config.RetryAttempts} attempts",
lastException!);
}
/// <summary>
/// Executes an operation with retry logic (void return).
/// </summary>
/// <param name="operation">The asynchronous operation to execute.</param>
/// <param name="operationName">The operation name used for logging.</param>
/// <param name="cancellationToken">A token used to cancel retry delays.</param>
public async Task ExecuteAsync(
Func<Task> operation,
string operationName,
CancellationToken cancellationToken = default)
/// <summary>
/// Executes an operation with retry logic (void return).
/// </summary>
/// <param name="operation">The asynchronous operation to execute.</param>
/// <param name="operationName">The operation name used for logging.</param>
/// <param name="cancellationToken">A token used to cancel retry delays.</param>
public async Task ExecuteAsync(
Func<Task> operation,
string operationName,
CancellationToken cancellationToken = default)
{
await ExecuteAsync(async () =>
{
@@ -104,13 +102,13 @@ public class RetryPolicy : IRetryPolicy
private static bool IsTransient(Exception ex)
{
// Network errors are typically transient
if (ex is NetworkException or System.Net.Sockets.SocketException or System.IO.IOException)
if (ex is NetworkException or SocketException or IOException)
return true;
// Timeout errors are transient
if (ex is Exceptions.TimeoutException or OperationCanceledException)
if (ex is TimeoutException or OperationCanceledException)
return true;
return false;
}
}
}