Exemplo n.º 1
0
        async Task <T> ISqlCommandExecutor.ExecuteQueryAsync <T>(
            IActivityMonitor monitor,
            SqlConnection connection,
            SqlTransaction transaction,
            SqlCommand cmd,
            Func <SqlCommand, CancellationToken, Task <T> > innerExecutor,
            CancellationToken cancellationToken)
        {
            Debug.Assert(connection != null && connection.State == System.Data.ConnectionState.Open);
            DateTime start      = DateTime.UtcNow;
            int      retryCount = 0;
            List <SqlDetailedException> previous = null;
            T result;

            for (; ;)
            {
                SqlDetailedException e = null;
                try
                {
                    cmd.Connection  = connection;
                    cmd.Transaction = transaction;
                    OnCommandExecuting(cmd, retryCount);

                    result = await innerExecutor(cmd, cancellationToken).ConfigureAwait(false);

                    break;
                }
                catch (IOException ex)
                {
                    e = SqlDetailedException.Create(cmd, ex, retryCount++);
                }
                catch (SqlException ex)
                {
                    e = SqlDetailedException.Create(cmd, ex, retryCount++);
                }
                catch (Exception ex)
                {
                    Monitor.Fatal(ex);
                    throw;
                }
                Debug.Assert(e != null);
                Monitor.Error(e);
                if (previous == null)
                {
                    previous = new List <SqlDetailedException>();
                }
                TimeSpan retry = OnCommandError(cmd, connection, e, previous, start);
                if (retry.Ticks < 0 ||
                    retry == TimeSpan.MaxValue ||
                    previous.Count > 1000)
                {
                    throw e;
                }
                previous.Add(e);
                await Task.Delay(retry).ConfigureAwait(false);
            }
            OnCommandExecuted(cmd, retryCount, result);
            return(result);
        }
Exemplo n.º 2
0
 /// <summary>
 /// Extension point called after a command failed.
 /// At this level, this method does nothing and returns <see cref="TimeSpan.MaxValue"/>: no retry will be done.
 /// <para>
 /// Note that any negative TimeSpan as well as TimeSpan.MaxValue will result in
 /// the <see cref="SqlDetailedException"/> being thrown.
 /// </para>
 /// </summary>
 /// <param name="cmd">The executing command.</param>
 /// <param name="c">The connection.</param>
 /// <param name="ex">The exception caught and wrapped in a <see cref="SqlDetailedException"/>.</param>
 /// <param name="previous">Previous errors when retries have been made. Empty on the first error.</param>
 /// <param name="firstExecutionTimeUtc">The Utc time of the first try.</param>
 /// <returns>The time span to retry. A negative time span or <see cref="TimeSpan.MaxValue"/> to skip retry.</returns>
 protected virtual TimeSpan OnCommandError(
     SqlCommand cmd,
     SqlConnection c,
     SqlDetailedException ex,
     IReadOnlyList <SqlDetailedException> previous,
     DateTime firstExecutionTimeUtc) => TimeSpan.MaxValue;