Skip to content

Commit 3e0b444

Browse files
benrr101edwardneal
andauthored
Allow errors with negative numbers to be considered transient (#2896) (#3185)
Only thing failing is merge code coverage, will push this through. Co-authored-by: Edward Neal <55035479+edwardneal@users.noreply.github.com>
1 parent 881c490 commit 3e0b444

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicLoader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ private static ICollection<int> SplitErrorNumberList(string list)
314314
HashSet<int> set = new HashSet<int>();
315315
for (int index = 0; index < parts.Length; index++)
316316
{
317-
if (int.TryParse(parts[index], System.Globalization.NumberStyles.AllowLeadingWhite | System.Globalization.NumberStyles.AllowTrailingWhite, null, out int value))
317+
if (int.TryParse(parts[index], System.Globalization.NumberStyles.Integer, null, out int value))
318318
{
319319
set.Add(value);
320320
}

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/RetryLogicConfigHelper.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public class RetryLogicConfigHelper
2828

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

31+
private const string CreateExceptionMethodName = "CreateException";
32+
private const string AddMethodName = "Add";
33+
3134
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";
3235

3336
private static readonly Random s_random = new Random();
@@ -36,13 +39,23 @@ public class RetryLogicConfigHelper
3639
private static readonly Type s_appContextSwitchManagerType = s_sqlClientAssembly.GetType(AppContextSwitchManagerTypeName);
3740
private static readonly Type s_sqlretrylogicType = s_sqlClientAssembly.GetType(SqlRetryLogicTypeName);
3841
private static readonly Type s_configurationLoaderType = s_sqlClientAssembly.GetType(ConfigurationLoaderTypeName);
42+
private static readonly Type s_sqlErrorType = typeof(SqlError);
43+
private static readonly Type s_sqlErrorCollectionType = typeof(SqlErrorCollection);
3944
private static readonly Type[] s_cfgLoaderParamsType = new Type[]
4045
{
4146
s_sqlClientAssembly.GetType(InterfaceCnnCfgTypeName),
4247
s_sqlClientAssembly.GetType(InterfaceCmdCfgTypeName),
4348
typeof(string), typeof(string)
4449
};
50+
private static readonly Type[] s_sqlErrorParamsType = new Type[]
51+
{
52+
typeof(int), typeof(byte), typeof(byte),
53+
typeof(string), typeof(string), typeof(string),
54+
typeof(int), typeof(Exception)
55+
};
4556
private static readonly ConstructorInfo s_loaderCtorInfo = s_configurationLoaderType.GetConstructor(s_cfgLoaderParamsType);
57+
private static readonly ConstructorInfo s_sqlErrorCtorInfo = s_sqlErrorType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, s_sqlErrorParamsType, null);
58+
private static readonly ConstructorInfo s_sqlErrorCollectionCtorInfo = s_sqlErrorCollectionType.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, Type.EmptyTypes, null);
4659

4760
public static object CreateLoader(RetryLogicConfigs cnnConfig, RetryLogicConfigs cmdConfig)
4861
{
@@ -164,6 +177,22 @@ public static RetryLogicConfigs CreateRandomConfig(string method, string authori
164177
};
165178
}
166179

180+
public static SqlException CreateSqlException(int errorNumber)
181+
{
182+
MethodInfo addSqlErrorMethod = typeof(SqlErrorCollection).GetMethod(AddMethodName, BindingFlags.Instance | BindingFlags.NonPublic);
183+
MethodInfo createExceptionMethod = typeof(SqlException).GetMethod(CreateExceptionMethodName, BindingFlags.Static | BindingFlags.NonPublic,
184+
null, new Type[] { typeof(SqlErrorCollection), typeof(string) }, null);
185+
186+
SqlError sqlError = s_sqlErrorCtorInfo.Invoke(new object[] { errorNumber, (byte)0, (byte)0, string.Empty, string.Empty, string.Empty, 0, null }) as SqlError;
187+
SqlErrorCollection sqlErrorCollection = s_sqlErrorCollectionCtorInfo.Invoke(new object[0] { }) as SqlErrorCollection;
188+
189+
addSqlErrorMethod.Invoke(sqlErrorCollection, new object[] { sqlError });
190+
191+
SqlException sqlException = createExceptionMethod.Invoke(null, new object[] { sqlErrorCollection, string.Empty }) as SqlException;
192+
193+
return sqlException;
194+
}
195+
167196
private static TimeSpan GenerateTimeSpan(TimeSpan start, TimeSpan end)
168197
{
169198
int max = (int)(end - start).TotalSeconds;

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/SqlConfigurationManagerReliabilityTest.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,30 @@ public void InvalidTransientError(string errors)
222222
}
223223
#endregion
224224

225+
#region Valid Configurations
226+
[Theory]
227+
[InlineData("-1,1,2,3")]
228+
[InlineData("-1, 1, 2 , 3, -2")]
229+
[InlineData("")]
230+
public void ValidTransientError(string errors)
231+
{
232+
string[] transientErrorNumbers = errors.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
233+
RetryLogicConfigs cnnCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix);
234+
cnnCfg.TransientErrors = errors;
235+
RetryLogicConfigs cmdCfg = RetryLogicConfigHelper.CreateRandomConfig(RetryLogicConfigHelper.RetryMethodName_Fix, @"Don't care!");
236+
237+
RetryLogicConfigHelper.ReturnLoaderAndProviders(cnnCfg, cmdCfg, out SqlRetryLogicBaseProvider cnnProvider, out _);
238+
239+
foreach(string errorString in transientErrorNumbers)
240+
{
241+
int errorNumber = int.Parse(errorString.Trim());
242+
SqlException transientException = RetryLogicConfigHelper.CreateSqlException(errorNumber);
243+
244+
Assert.True(cnnProvider.RetryLogic.TransientPredicate(transientException), $"Error {errorNumber} is not considered transient by the predicate.");
245+
}
246+
}
247+
#endregion
248+
225249
#region private methods
226250
private void TestConnection(SqlRetryLogicBaseProvider provider, RetryLogicConfigs cnfig)
227251
{

0 commit comments

Comments
 (0)