Dotnet C#에서 SQL 서버 연결을 위한 구성 가능한 재시도 논리
사용자 지정 구성 가능한 재시도 논리 클래스를 정의합니다.
열거자: 고정된 시간 간격 시퀀스를 정의하고 허용 가능한 시간 범위를 2분에서 4분으로 확장합니다.
public class CustomEnumerator : SqlRetryIntervalBaseEnumerator
{
// Set the maximum acceptable time to 4 minutes
private readonly TimeSpan _maxValue = TimeSpan.FromMinutes(4);
public CustomEnumerator(TimeSpan timeInterval, TimeSpan maxTime, TimeSpan minTime)
: base(timeInterval, maxTime, minTime) {}
// Return fixed time on each request
protected override TimeSpan GetNextInterval()
{
return GapTimeInterval;
}
// Override the validate method with the new time range validation
protected override void Validate(TimeSpan timeInterval, TimeSpan maxTimeInterval, TimeSpan minTimeInterval)
{
if (minTimeInterval < TimeSpan.Zero || minTimeInterval > _maxValue)
{
throw new ArgumentOutOfRangeException(nameof(minTimeInterval));
}
if (maxTimeInterval < TimeSpan.Zero || maxTimeInterval > _maxValue)
{
throw new ArgumentOutOfRangeException(nameof(maxTimeInterval));
}
if (timeInterval < TimeSpan.Zero || timeInterval > _maxValue)
{
throw new ArgumentOutOfRangeException(nameof(timeInterval));
}
if (maxTimeInterval < minTimeInterval)
{
throw new ArgumentOutOfRangeException(nameof(minTimeInterval));
}
}
}
재시도 논리: 활성 트랜잭션의 일부가 아닌 모든 명령에 대해 재시도 논리를 구현합니다. 재시도 횟수를 60에서 20으로 줄입니다.
public class CustomRetryLogic : SqlRetryLogicBase
{
// Maximum number of attempts
private const int maxAttempts = 20;
public CustomRetryLogic(int numberOfTries,
SqlRetryIntervalBaseEnumerator enumerator,
Predicate<Exception> transientPredicate)
{
if (!(numberOfTries > 0 && numberOfTries <= maxAttempts))
{
// 'numberOfTries' should be between 1 and 20.
throw new ArgumentOutOfRangeException(nameof(numberOfTries));
}
// Assign parameters to the relevant properties
NumberOfTries = numberOfTries;
RetryIntervalEnumerator = enumerator;
TransientPredicate = transientPredicate;
Current = 0;
}
// Prepare this object for the next round
public override void Reset()
{
Current = 0;
RetryIntervalEnumerator.Reset();
}
public override bool TryNextInterval(out TimeSpan intervalTime)
{
intervalTime = TimeSpan.Zero;
// First try has occurred before starting the retry process.
// Check if retry is still allowed
bool result = Current < NumberOfTries - 1;
if (result)
{
// Increase the number of attempts
Current++;
// It's okay if the RetryIntervalEnumerator gets to the last value before we've reached our maximum number of attempts.
// MoveNext() will simply leave the enumerator on the final interval value and we will repeat that for the final attempts.
RetryIntervalEnumerator.MoveNext();
// Receive the current time from enumerator
intervalTime = RetryIntervalEnumerator.Current;
}
return result;
}
}
공급자: 재시도 이벤트 없이 동기 작업을 재시도하는 재시도 공급자를 구현합니다. 기존 SqlException 일시적 예외 오류 번호에 TimeoutException을 추가합니다.
public class CustomProvider : SqlRetryLogicBaseProvider
{
// Preserve the given retryLogic on creation
public CustomProvider(SqlRetryLogicBase retryLogic)
{
RetryLogic = retryLogic;
}
public override TResult Execute<TResult>(object sender, Func<TResult> function)
{
// Create a list to save transient exceptions to report later if necessary
IList<Exception> exceptions = new List<Exception>();
// Prepare it before reusing
RetryLogic.Reset();
// Create an infinite loop to attempt the defined maximum number of tries
do
{
try
{
// Try to invoke the function
return function.Invoke();
}
// Catch any type of exception for further investigation
catch (Exception e)
{
// Ask the RetryLogic object if this exception is a transient error
if (RetryLogic.TransientPredicate(e))
{
// Add the exception to the list of exceptions we've retried on
exceptions.Add(e);
// Ask the RetryLogic for the next delay time before the next attempt to run the function
if (RetryLogic.TryNextInterval(out TimeSpan gapTime))
{
Console.WriteLine($"Wait for {gapTime} before next try");
// Wait before next attempt
Thread.Sleep(gapTime);
}
else
{
// Number of attempts has exceeded the maximum number of tries
throw new AggregateException("The number of retries has exceeded the maximum number of attempts.", exceptions);
}
}
else
{
// If the exception wasn't a transient failure throw the original exception
throw;
}
}
} while (true);
}
public override Task<TResult> ExecuteAsync<TResult>(object sender, Func<Task<TResult>> function, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public override Task ExecuteAsync(object sender, Func<Task> function, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
}
정의된 사용자 지정 유형으로 구성된 재시도 공급자 인스턴스를 만듭니다.
public static SqlRetryLogicBaseProvider CreateCustomProvider(SqlRetryLogicOption options)
{
// 1. create an enumerator instance
CustomEnumerator customEnumerator = new CustomEnumerator(options.DeltaTime, options.MaxTimeInterval, options.MinTimeInterval);
// 2. Use the enumerator object to create a new RetryLogic instance
CustomRetryLogic customRetryLogic = new CustomRetryLogic(5, customEnumerator, (e) => TransientErrorsCondition(e, options.TransientErrors));
// 3. Create a provider using the RetryLogic object
CustomProvider customProvider = new CustomProvider(customRetryLogic);
return customProvider;
}
다음 함수는 주어진 재시도 가능한 예외 목록과 특수한 TimeoutException 예외를 사용하여 예외를 평가하여 재시도 가능한지 확인합니다.
// Return true if the exception is a transient fault.
private static bool TransientErrorsCondition(Exception e, IEnumerable<int> retriableConditions)
{
bool result = false;
// Assess only SqlExceptions
if (retriableConditions != null && e is SqlException ex)
{
foreach (SqlError item in ex.Errors)
{
// Check each error number to see if it is a retriable error number
if (retriableConditions.Contains(item.Number))
{
result = true;
break;
}
}
}
// Other types of exceptions can also be assessed
else if (e is TimeoutException)
{
result = true;
}
return result;
}
사용자 지정 재시도 논리를 사용합니다.
재시도 논리 매개변수를 정의합니다.
// Define the retry logic parameters
var options = new SqlRetryLogicOption()
{
// Tries 5 times before throwing an exception
NumberOfTries = 5,
// Preferred gap time to delay before retry
DeltaTime = TimeSpan.FromSeconds(1),
// Maximum gap time for each delay time before retry
MaxTimeInterval = TimeSpan.FromSeconds(20),
// SqlException retriable error numbers
TransientErrors = new int[] { 4060, 1024, 1025}
};
사용자 지정 재시도 논리를 사용합니다.
재시도 논리 매개변수를 정의합니다.
// Define the retry logic parameters
var options = new SqlRetryLogicOption()
{
// Tries 5 times before throwing an exception
NumberOfTries = 5,
// Preferred gap time to delay before retry
DeltaTime = TimeSpan.FromSeconds(1),
// Maximum gap time for each delay time before retry
MaxTimeInterval = TimeSpan.FromSeconds(20),
// SqlException retriable error numbers
TransientErrors = new int[] { 4060, 1024, 1025}
};
사용자 지정 재시도 공급자를 만듭니다.
// Create a custom retry logic provider
SqlRetryLogicBaseProvider provider = CustomRetry.CreateCustomProvider(options);
재시도 공급자를 SqlConnection.RetryLogicProvider 또는 SqlCommand.RetryLogicProvider에 할당합니다.
// Assumes that connection is a valid SqlConnection object
// Set the retry logic provider on the connection instance
connection.RetryLogicProvider = provider;
// Establishing the connection will trigger retry if one of the given transient failure occurs.
connection.Open();
사용하기 전에 구성 가능한 재시도 로직 스위치를 활성화하는 것을 잊지 마십시오. 자세한 내용은 see Enable configurable retry logic .
참조 :
https://docs.microsoft.com/en-us/sql/connect/ado-net/configurable-retry-logic-core-apis-sqlclient?view=sql-server-ver15
Reference
이 문제에 관하여(Dotnet C#에서 SQL 서버 연결을 위한 구성 가능한 재시도 논리), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ssanjeevi/configurable-retry-logic-for-sql-server-connection-in-dotnet-c-2c64텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)