Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

5.2 | Port PR 2896 (Allow errors with negative numbers to be considered transient) #3089

Open
wants to merge 1 commit into
base: release/5.2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ private static ICollection<int> SplitErrorNumberList(string list)
HashSet<int> set = new HashSet<int>();
for (int index = 0; index < parts.Length; index++)
{
if (int.TryParse(parts[index], System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowTrailingWhite, null, out int value))
if (int.TryParse(parts[index], System.Globalization.NumberStyles.Integer, null, out int value))
{
set.Add(value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ public class RetryLogicConfigHelper

private const string SqlRetryLogicTypeName = "Microsoft.Data.SqlClient.SqlRetryLogic";

private const string CreateExceptionMethodName = "CreateException";
private const string AddMethodName = "Add";

public const string DefaultTransientErrors = "1204, 1205, 1222, 49918, 49919, 49920, 4060, 4221, 40143, 40613, 40501, 40540, 40197, 42108, 42109, 10929, 10928, 10060, 10054, 10053, 997, 233, 64, 20, 0, -2, 207, 102, 2812";

private static readonly Random s_random = new Random();
Expand All @@ -36,13 +39,23 @@ public class RetryLogicConfigHelper
private static readonly Type s_appContextSwitchManagerType = s_sqlClientAssembly.GetType(AppContextSwitchManagerTypeName);
private static readonly Type s_sqlretrylogicType = s_sqlClientAssembly.GetType(SqlRetryLogicTypeName);
private static readonly Type s_configurationLoaderType = s_sqlClientAssembly.GetType(ConfigurationLoaderTypeName);
private static readonly Type s_sqlErrorType = typeof(SqlError);
private static readonly Type s_sqlErrorCollectionType = typeof(SqlErrorCollection);
private static readonly Type[] s_cfgLoaderParamsType = new Type[]
{
s_sqlClientAssembly.GetType(InterfaceCnnCfgTypeName),
s_sqlClientAssembly.GetType(InterfaceCmdCfgTypeName),
typeof(string), typeof(string)
};
private static readonly Type[] s_sqlErrorParamsType = new Type[]
{
typeof(int), typeof(byte), typeof(byte),
typeof(string), typeof(string), typeof(string),
typeof(int), typeof(Exception)
};
private static readonly ConstructorInfo s_loaderCtorInfo = s_configurationLoaderType.GetConstructor(s_cfgLoaderParamsType);
private static readonly ConstructorInfo s_sqlErrorCtorInfo = s_sqlErrorType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, s_sqlErrorParamsType, null);
private static readonly ConstructorInfo s_sqlErrorCollectionCtorInfo = s_sqlErrorCollectionType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);

public static object CreateLoader(RetryLogicConfigs cnnConfig, RetryLogicConfigs cmdConfig)
{
Expand Down Expand Up @@ -164,6 +177,22 @@ public static RetryLogicConfigs CreateRandomConfig(string method, string authori
};
}

public static SqlException CreateSqlException(int errorNumber)
{
MethodInfo addSqlErrorMethod = typeof(SqlErrorCollection).GetMethod(AddMethodName, BindingFlags.Instance | BindingFlags.NonPublic);
MethodInfo createExceptionMethod = typeof(SqlException).GetMethod(CreateExceptionMethodName, BindingFlags.Static | BindingFlags.NonPublic,
null, new Type[] { typeof(SqlErrorCollection), typeof(string) }, null);

SqlError sqlError = s_sqlErrorCtorInfo.Invoke(new object[] { errorNumber, (byte)0, (byte)0, string.Empty, string.Empty, string.Empty, 0, null }) as SqlError;
SqlErrorCollection sqlErrorCollection = s_sqlErrorCollectionCtorInfo.Invoke(new object[0] { }) as SqlErrorCollection;

addSqlErrorMethod.Invoke(sqlErrorCollection, new object[] { sqlError });

SqlException sqlException = createExceptionMethod.Invoke(null, new object[] { sqlErrorCollection, string.Empty }) as SqlException;

return sqlException;
}

private static TimeSpan GenerateTimeSpan(TimeSpan start, TimeSpan end)
{
int max = (int)(end - start).TotalSeconds;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,30 @@ public void InvalidTransientError(string errors)
}
#endregion

#region Valid Configurations
[Theory]
[InlineData("-1,1,2,3")]
[InlineData("-1, 1, 2 , 3, -2")]
[InlineData("")]
public void ValidTransientError(string errors)
{
string[] transientErrorNumbers = errors.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
RetryLogicConfigs cnnCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix);
cnnCfg.TransientErrors = errors;
RetryLogicConfigs cmdCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix, @"Don't care!");

RetryLogicConfigHelper.ReturnLoaderAndProviders(cnnCfg, cmdCfg, out SqlRetryLogicBaseProvider cnnProvider, out _);

foreach(string errorString in transientErrorNumbers)
{
int errorNumber = int.Parse(errorString.Trim());
SqlException transientException = RetryLogicConfigHelper.CreateSqlException(errorNumber);

Assert.True(cnnProvider.RetryLogic.TransientPredicate(transientException), $"Error {errorNumber} is not considered transient by the predicate.");
}
}
#endregion

#region private methods
private void TestConnection(SqlRetryLogicBaseProvider provider, RetryLogicConfigs cnfig)
{
Expand Down
Loading