You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I use SqlClient 3.0 RetryLogic to transparently log extensive information about failed request.
When a retry logic provider is used with SqlCommand.ExecuteScalarAsync, RetryLogicProvider.ExecuteAsync is called twice recursively : first time from SqlCommand.ExecuteScalarAsync, and second time from the inner SqlCommand.ExecuteReaderAsync.
Here is a stack trace from the second call :
MultipleRetryCall.dll!MultipleRetryCall.ErrorInfoRetryLogicProvider.ExecuteAsync<Microsoft.Data.SqlClient.SqlDataReader>(object sender, System.Func<System.Threading.Tasks.Task<Microsoft.Data.SqlClient.SqlDataReader>> function, System.Threading.CancellationToken cancellationToken) Ligne 77
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.InternalExecuteReaderWithRetryAsync(System.Data.CommandBehavior behavior, System.Threading.CancellationToken cancellationToken) Ligne 2548
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.ExecuteReaderAsync(System.Data.CommandBehavior behavior, System.Threading.CancellationToken cancellationToken) Ligne 2543
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.ExecuteReaderAsync(System.Threading.CancellationToken cancellationToken) Ligne 2538
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.InternalExecuteScalarAsync(System.Threading.CancellationToken cancellationToken) Ligne 2635
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.InternalExecuteScalarWithRetryAsync.AnonymousMethod__0() Ligne 2626
MultipleRetryCall.dll!MultipleRetryCall.ErrorInfoRetryLogicProvider.LogCallsAsync(object sender, System.Func<System.Threading.Tasks.Task> function) Ligne 65
MultipleRetryCall.dll!MultipleRetryCall.ErrorInfoRetryLogicProvider.ExecuteAsync.AnonymousMethod__0() Ligne 81
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlRetryLogicProvider.ExecuteAsync(object sender, System.Func<System.Threading.Tasks.Task> function, System.Threading.CancellationToken cancellationToken) Ligne 106
MultipleRetryCall.dll!MultipleRetryCall.ErrorInfoRetryLogicProvider.ExecuteAsync(object sender, System.Func<System.Threading.Tasks.Task> function, System.Threading.CancellationToken cancellationToken) Ligne 81
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.InternalExecuteScalarWithRetryAsync(System.Threading.CancellationToken cancellationToken) Ligne 2626
Microsoft.Data.SqlClient.dll!Microsoft.Data.SqlClient.SqlCommand.ExecuteScalarAsync(System.Threading.CancellationToken cancellationToken) Ligne 2621
System.Data.Common.dll!System.Data.Common.DbCommand.ExecuteScalarAsync() Ligne 191
MultipleRetryCall.dll!MultipleRetryCall.Program.Main(string[] args) Ligne 147
(bold : custom code)
To reproduce
Define a SqlRetryLogicBaseProvider that encapsulate a FixedRetryProvider.
Execute* methods add logs before and after each inner call.
First part call ExecuteScalarAsync that will fail :
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting counter=1 thread=4
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 1
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting counter=2 thread=4
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 2
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 2
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 3
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 3
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 4
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 4
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping counter=2 thread=5
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 4
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping counter=1 thread=7
Error The number of retries has exceeded the maximum of 3 attempt(s). (Error) (Error) (Error) total tries = 4
Same call with ExecuteReaderAsync :
ExecuteReaderAsync failure with retry
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting counter=1 thread=7
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 1
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 1
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 2
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 2
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 3
LogCallsAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 3
ExecuteAsync<T> Microsoft.Data.SqlClient.SqlCommand Stopping counter=1 thread=5
Error The number of retries has exceeded the maximum of 3 attempt(s). (Error) (Error) (Error) total tries = 3
Same call with ExecuteScalar (Sync) :
ExecuteScalar failure with retry
Execute<T> Microsoft.Data.SqlClient.SqlCommand Starting counter=1 thread=5
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 1
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 1
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 2
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 2
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Starting inner 3
LogCalls<T> Microsoft.Data.SqlClient.SqlCommand Stopping inner 3
Execute<T> Microsoft.Data.SqlClient.SqlCommand Stopping counter=1 thread=5
Error The number of retries has exceeded the maximum of 3 attempt(s). (Error) (Error) (Error) total tries = 3
Describe the bug
I use SqlClient 3.0 RetryLogic to transparently log extensive information about failed request.
When a retry logic provider is used with SqlCommand.ExecuteScalarAsync, RetryLogicProvider.ExecuteAsync is called twice recursively : first time from SqlCommand.ExecuteScalarAsync, and second time from the inner SqlCommand.ExecuteReaderAsync.
Here is a stack trace from the second call :
(bold : custom code)
To reproduce
Define a SqlRetryLogicBaseProvider that encapsulate a FixedRetryProvider.
Execute* methods add logs before and after each inner call.
First part call ExecuteScalarAsync that will fail :
Same call with ExecuteReaderAsync :
Same call with ExecuteScalar (Sync) :
GIST
MultipleRetryCall.zip
Expected behavior
RetryLogicProvider should be called only once when used with ExecuteScalarAsync to be consistent with ExecuteScalar and ExecuteReaderAsync.
Further technical details
Microsoft.Data.SqlClient version: 3.0
.NET target: netcore3.1
SQL Server version: 14
Operating system: Windows 10
The text was updated successfully, but these errors were encountered: