Skip to content

Commit 831287f

Browse files
Remove Configurable Retry Logic safety switch (#1254)
1 parent 576fadb commit 831287f

File tree

11 files changed

+50
-162
lines changed

11 files changed

+50
-162
lines changed

BUILDGUIDE.md

-6
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,6 @@ Scaled decimal parameter truncation can be enabled by enabling the below AppCont
245245

246246
**"Switch.Microsoft.Data.SqlClient.TruncateScaledDecimal"**
247247

248-
## Enabling configurable retry logic
249-
250-
To use this feature, you must enable the following AppContext switch at application startup:
251-
252-
**"Switch.Microsoft.Data.SqlClient.EnableRetryLogic"**
253-
254248
## Enabling row version null behavior
255249

256250
`SqlDataReader` returns a `DBNull` value instead of an empty `byte[]`. To enable the legacy behavior, you must enable the following AppContext switch on application startup:

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ private SqlInternalConnectionTds InternalTdsConnection
506506
}
507507
}
508508

509-
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
509+
private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider);
510510

511511
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/RetryLogicProvider/*' />
512512
[Browsable(false)]
@@ -1101,7 +1101,7 @@ public override object ExecuteScalar()
11011101
statistics = SqlStatistics.StartTimer(Statistics);
11021102
WriteBeginExecuteEvent();
11031103
SqlDataReader ds;
1104-
ds = IsRetryEnabled ?
1104+
ds = IsProviderRetriable ?
11051105
RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, returnStream: true) :
11061106
RunExecuteReader(0, RunBehavior.ReturnImmediately, returnStream: true, method: nameof(ExecuteScalar));
11071107
success = true;
@@ -1192,7 +1192,7 @@ public override int ExecuteNonQuery()
11921192
{
11931193
statistics = SqlStatistics.StartTimer(Statistics);
11941194
WriteBeginExecuteEvent();
1195-
if (IsRetryEnabled)
1195+
if (IsProviderRetriable)
11961196
{
11971197
InternalExecuteNonQueryWithRetry(sendToPipe: false, timeout: CommandTimeout, out _, asyncWrite: false, inRetry: false);
11981198
}
@@ -1700,7 +1700,7 @@ public XmlReader ExecuteXmlReader()
17001700
WriteBeginExecuteEvent();
17011701
// use the reader to consume metadata
17021702
SqlDataReader ds;
1703-
ds = IsRetryEnabled ?
1703+
ds = IsProviderRetriable ?
17041704
RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true) :
17051705
RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, returnStream: true);
17061706
success = true;
@@ -2033,7 +2033,7 @@ protected override DbDataReader ExecuteDbDataReader(CommandBehavior behavior)
20332033
{
20342034
WriteBeginExecuteEvent();
20352035
statistics = SqlStatistics.StartTimer(Statistics);
2036-
return IsRetryEnabled ?
2036+
return IsProviderRetriable ?
20372037
RunExecuteReaderWithRetry(behavior, RunBehavior.ReturnImmediately, returnStream: true) :
20382038
RunExecuteReader(behavior, RunBehavior.ReturnImmediately, returnStream: true);
20392039
}
@@ -2535,7 +2535,7 @@ private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, bool is
25352535

25362536
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteNonQueryAsync[@name="CancellationToken"]/*'/>
25372537
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
2538-
=> IsRetryEnabled ?
2538+
=> IsProviderRetriable ?
25392539
InternalExecuteNonQueryWithRetryAsync(cancellationToken) :
25402540
InternalExecuteNonQueryAsync(cancellationToken);
25412541

@@ -2635,7 +2635,7 @@ protected override Task<DbDataReader> ExecuteDbDataReaderAsync(CommandBehavior b
26352635

26362636
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteReaderAsync[@name="commandBehaviorAndCancellationToken"]/*'/>
26372637
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
2638-
=> IsRetryEnabled ?
2638+
=> IsProviderRetriable ?
26392639
InternalExecuteReaderWithRetryAsync(behavior, cancellationToken) :
26402640
InternalExecuteReaderAsync(behavior, cancellationToken);
26412641

@@ -2808,7 +2808,7 @@ public Task<XmlReader> ExecuteXmlReaderAsync()
28082808

28092809
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteXmlReaderAsync[@name="CancellationToken"]/*'/>
28102810
public Task<XmlReader> ExecuteXmlReaderAsync(CancellationToken cancellationToken)
2811-
=> IsRetryEnabled ?
2811+
=> IsProviderRetriable ?
28122812
InternalExecuteXmlReaderWithRetryAsync(cancellationToken) :
28132813
InternalExecuteXmlReaderAsync(cancellationToken);
28142814

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ private static readonly ConcurrentDictionary<string, IList<string>> _ColumnEncry
114114
private static readonly Action<object> s_openAsyncCancel = OpenAsyncCancel;
115115
private static readonly Action<Task<object>, object> s_openAsyncComplete = OpenAsyncComplete;
116116

117-
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
117+
private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider);
118118

119119
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/RetryLogicProvider/*' />
120120
[Browsable(false)]
@@ -1324,7 +1324,7 @@ public void Open(SqlConnectionOverrides overrides)
13241324
try
13251325
{
13261326
statistics = SqlStatistics.StartTimer(Statistics);
1327-
if (!(IsRetryEnabled ? TryOpenWithRetry(null, overrides) : TryOpen(null, overrides)))
1327+
if (!(IsProviderRetriable ? TryOpenWithRetry(null, overrides) : TryOpen(null, overrides)))
13281328
{
13291329
throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
13301330
}
@@ -1575,7 +1575,7 @@ private Task InternalOpenWithRetryAsync(CancellationToken cancellationToken)
15751575

15761576
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/OpenAsync/*' />
15771577
public override Task OpenAsync(CancellationToken cancellationToken)
1578-
=> IsRetryEnabled ?
1578+
=> IsProviderRetriable ?
15791579
InternalOpenWithRetryAsync(cancellationToken) :
15801580
InternalOpenAsync(cancellationToken);
15811581

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs

+12-12
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,7 @@ private bool IsShiloh
620620
}
621621
}
622622

623-
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
623+
private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider);
624624

625625
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/RetryLogicProvider/*' />
626626
[
@@ -1382,7 +1382,7 @@ public override object ExecuteScalar()
13821382
statistics = SqlStatistics.StartTimer(Statistics);
13831383
WriteBeginExecuteEvent();
13841384
SqlDataReader ds;
1385-
ds = IsRetryEnabled ?
1385+
ds = IsProviderRetriable ?
13861386
RunExecuteReaderWithRetry(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar) :
13871387
RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar);
13881388
object result = CompleteExecuteScalar(ds, false);
@@ -1462,7 +1462,7 @@ public override int ExecuteNonQuery()
14621462
statistics = SqlStatistics.StartTimer(Statistics);
14631463
WriteBeginExecuteEvent();
14641464
bool usedCache;
1465-
if (IsRetryEnabled)
1465+
if (IsProviderRetriable)
14661466
{
14671467
InternalExecuteNonQueryWithRetry(ADP.ExecuteNonQuery, sendToPipe: false, CommandTimeout, out usedCache, asyncWrite: false, inRetry: false);
14681468
}
@@ -2092,7 +2092,7 @@ public XmlReader ExecuteXmlReader()
20922092

20932093
// use the reader to consume metadata
20942094
SqlDataReader ds;
2095-
ds = IsRetryEnabled ?
2095+
ds = IsProviderRetriable ?
20962096
RunExecuteReaderWithRetry(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader) :
20972097
RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.ExecuteXmlReader);
20982098
XmlReader result = CompleteXmlReader(ds);
@@ -2415,7 +2415,7 @@ private SqlDataReader ExecuteReaderWithRetry(CommandBehavior behavior, string me
24152415
try
24162416
{
24172417
statistics = SqlStatistics.StartTimer(Statistics);
2418-
return IsRetryEnabled ?
2418+
return IsProviderRetriable ?
24192419
ExecuteReaderWithRetry(CommandBehavior.Default, ADP.ExecuteReader) :
24202420
ExecuteReader(CommandBehavior.Default, ADP.ExecuteReader);
24212421
}
@@ -2433,7 +2433,7 @@ private SqlDataReader ExecuteReaderWithRetry(CommandBehavior behavior, string me
24332433
{
24342434
SqlClientEventSource.Log.TryCorrelationTraceEvent("<sc.SqlCommand.ExecuteReader|API|Correlation> ObjectID {0}, behavior={1}, ActivityID {2}", ObjectID, (int)behavior, ActivityCorrelator.Current);
24352435

2436-
return IsRetryEnabled ?
2436+
return IsProviderRetriable ?
24372437
ExecuteReaderWithRetry(behavior, ADP.ExecuteReader) :
24382438
ExecuteReader(behavior, ADP.ExecuteReader);
24392439
}
@@ -2945,7 +2945,7 @@ private Task<int> InternalExecuteNonQueryWithRetryAsync(CancellationToken cancel
29452945

29462946
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteNonQueryAsync[@name="CancellationToken"]/*'/>
29472947
public override Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken)
2948-
=> IsRetryEnabled ?
2948+
=> IsProviderRetriable ?
29492949
InternalExecuteNonQueryWithRetryAsync(cancellationToken) :
29502950
InternalExecuteNonQueryAsync(cancellationToken);
29512951

@@ -3024,25 +3024,25 @@ private Task<SqlDataReader> InternalExecuteReaderWithRetryAsync(CommandBehavior
30243024

30253025
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteReaderAsync[@name="default"]/*'/>
30263026
new public Task<SqlDataReader> ExecuteReaderAsync()
3027-
=> IsRetryEnabled ?
3027+
=> IsProviderRetriable ?
30283028
InternalExecuteReaderWithRetryAsync(CommandBehavior.Default, CancellationToken.None) :
30293029
InternalExecuteReaderAsync(CommandBehavior.Default, CancellationToken.None);
30303030

30313031
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteReaderAsync[@name="CommandBehavior"]/*'/>
30323032
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior)
3033-
=> IsRetryEnabled ?
3033+
=> IsProviderRetriable ?
30343034
InternalExecuteReaderWithRetryAsync(behavior, CancellationToken.None) :
30353035
InternalExecuteReaderAsync(behavior, CancellationToken.None);
30363036

30373037
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteReaderAsync[@name="CancellationToken"]/*'/>
30383038
new public Task<SqlDataReader> ExecuteReaderAsync(CancellationToken cancellationToken)
3039-
=> IsRetryEnabled ?
3039+
=> IsProviderRetriable ?
30403040
InternalExecuteReaderWithRetryAsync(CommandBehavior.Default, cancellationToken) :
30413041
InternalExecuteReaderAsync(CommandBehavior.Default, cancellationToken);
30423042

30433043
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteReaderAsync[@name="commandBehaviorAndCancellationToken"]/*'/>
30443044
new public Task<SqlDataReader> ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
3045-
=> IsRetryEnabled ?
3045+
=> IsProviderRetriable ?
30463046
InternalExecuteReaderWithRetryAsync(behavior, cancellationToken) :
30473047
InternalExecuteReaderAsync(behavior, cancellationToken);
30483048

@@ -3188,7 +3188,7 @@ private Task<XmlReader> InternalExecuteXmlReaderWithRetryAsync(CancellationToken
31883188

31893189
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml' path='docs/members[@name="SqlCommand"]/ExecuteXmlReaderAsync[@name="CancellationToken"]/*'/>
31903190
public Task<XmlReader> ExecuteXmlReaderAsync(CancellationToken cancellationToken)
3191-
=> IsRetryEnabled ?
3191+
=> IsProviderRetriable ?
31923192
InternalExecuteXmlReaderWithRetryAsync(cancellationToken) :
31933193
InternalExecuteXmlReaderAsync(cancellationToken);
31943194

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ internal List<string> GetColumnEncryptionCustomKeyStoreProvidersNames()
310310

311311
// Retry Logic
312312
private SqlRetryLogicBaseProvider _retryLogicProvider;
313-
private static bool IsRetryEnabled => LocalAppContextSwitches.IsRetryEnabled;
313+
private bool IsProviderRetriable => SqlConfigurableRetryFactory.IsRetriable(RetryLogicProvider);
314314

315315
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml' path='docs/members[@name="SqlConnection"]/RetryLogicProvider/*' />
316316
[
@@ -1648,7 +1648,7 @@ public void Open(SqlConnectionOverrides overrides)
16481648
{
16491649
statistics = SqlStatistics.StartTimer(Statistics);
16501650

1651-
if (!(IsRetryEnabled ? TryOpenWithRetry(null, overrides) : TryOpen(null, overrides)))
1651+
if (!(IsProviderRetriable ? TryOpenWithRetry(null, overrides) : TryOpen(null, overrides)))
16521652
{
16531653
throw ADP.InternalError(ADP.InternalErrorCode.SynchronousConnectReturnedPending);
16541654
}
@@ -1882,7 +1882,7 @@ private Task InternalOpenWithRetryAsync(CancellationToken cancellationToken)
18821882

18831883
/// <include file='..\..\..\..\..\..\..\doc\snippets\Microsoft.Data.SqlClient\SqlConnection.xml' path='docs/members[@name="SqlConnection"]/OpenAsync/*' />
18841884
public override Task OpenAsync(CancellationToken cancellationToken)
1885-
=> IsRetryEnabled ?
1885+
=> IsProviderRetriable ?
18861886
InternalOpenWithRetryAsync(cancellationToken) :
18871887
InternalOpenAsync(cancellationToken);
18881888

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs

-17
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,10 @@ internal static partial class LocalAppContextSwitches
1414
internal const string MakeReadAsyncBlockingString = @"Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking";
1515
internal const string LegacyRowVersionNullString = @"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior";
1616
internal const string UseSystemDefaultSecureProtocolsString = @"Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols";
17-
// safety switch
18-
internal const string EnableRetryLogicSwitch = "Switch.Microsoft.Data.SqlClient.EnableRetryLogic";
1917

2018
private static bool _makeReadAsyncBlocking;
2119
private static bool? s_LegacyRowVersionNullBehavior;
2220
private static bool? s_UseSystemDefaultSecureProtocols;
23-
private static bool? s_isRetryEnabled = null;
2421

2522
#if !NETFRAMEWORK
2623
static LocalAppContextSwitches()
@@ -38,20 +35,6 @@ static LocalAppContextSwitches()
3835
}
3936
#endif
4037

41-
internal static bool IsRetryEnabled
42-
{
43-
get
44-
{
45-
if (s_isRetryEnabled is null)
46-
{
47-
bool result;
48-
result = AppContext.TryGetSwitch(EnableRetryLogicSwitch, out result) ? result : false;
49-
s_isRetryEnabled = result;
50-
}
51-
return s_isRetryEnabled.Value;
52-
}
53-
}
54-
5538
public static bool MakeReadAsyncBlocking
5639
{
5740
[MethodImpl(MethodImplOptions.AggressiveInlining)]

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

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ public static SqlRetryLogicBaseProvider CreateNoneRetryProvider()
101101
return new SqlRetryLogicProvider(retryLogic);
102102
}
103103

104+
/// <summary>
105+
/// Verifies the provider which is not null and doesn't include SqlNoneIntervalEnumerator enumerator object.
106+
/// </summary>
107+
internal static bool IsRetriable(SqlRetryLogicBaseProvider provider)
108+
=> provider is not null && (provider.RetryLogic is null || provider.RetryLogic.RetryIntervalEnumerator is not SqlNoneIntervalEnumerator);
109+
104110
/// Return true if the exception is a transient fault.
105111
private static bool TransientErrorsCondition(Exception e, IEnumerable<int> retriableConditions)
106112
{

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

+3-9
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,8 @@ public static SqlRetryLogicBaseProvider GetConnectionProvider(object loader)
9191
public static SqlRetryLogicBaseProvider GetCommandProvider(object loader)
9292
=> GetValue<SqlRetryLogicBaseProvider>(loader, s_configurationLoaderType, "CommandProvider");
9393

94-
public static void AssessProvider(SqlRetryLogicBaseProvider provider, RetryLogicConfigs option, bool switchValue)
95-
{
96-
AssessRetryLogic(provider.RetryLogic, option);
97-
98-
AppContext.TryGetSwitch(RetryLogicTestHelper.RetryAppContextSwitch, out bool value);
99-
Assert.Equal(switchValue, value);
100-
}
94+
public static void AssessProvider(SqlRetryLogicBaseProvider provider, RetryLogicConfigs option)
95+
=> AssessRetryLogic(provider.RetryLogic, option);
10196

10297
public static void AssessRetryLogic(SqlRetryLogicBase retryLogic, RetryLogicConfigs option)
10398
{
@@ -142,9 +137,8 @@ public static IEnumerable<object[]> GetIivalidTimes()
142137
}
143138
}
144139

145-
public static object ReturnLoaderAndProviders(RetryLogicConfigs cnnCfg, RetryLogicConfigs cmdCfg, bool switchValue, out SqlRetryLogicBaseProvider cnnProvider, out SqlRetryLogicBaseProvider cmdProvider)
140+
public static object ReturnLoaderAndProviders(RetryLogicConfigs cnnCfg, RetryLogicConfigs cmdCfg, out SqlRetryLogicBaseProvider cnnProvider, out SqlRetryLogicBaseProvider cmdProvider)
146141
{
147-
ApplyContextSwitchByManager(RetryLogicTestHelper.RetryAppContextSwitch, switchValue);
148142
var loaderObj = CreateLoader(cnnCfg, cmdCfg);
149143
cnnProvider = GetConnectionProvider(loaderObj);
150144
cmdProvider = GetCommandProvider(loaderObj);

0 commit comments

Comments
 (0)