// public static methods
 public static TResult Execute <TResult>(IRetryableReadOperation <TResult> operation, IReadBinding binding, bool retryRequested, CancellationToken cancellationToken)
 {
     using (var context = RetryableReadContext.Create(binding, retryRequested, cancellationToken))
     {
         return(Execute(operation, context, cancellationToken));
     }
 }
 public static async Task <TResult> ExecuteAsync <TResult>(IRetryableReadOperation <TResult> operation, IReadBinding binding, bool retryRequested, CancellationToken cancellationToken)
 {
     using (var context = await RetryableReadContext.CreateAsync(binding, retryRequested, cancellationToken).ConfigureAwait(false))
     {
         return(await ExecuteAsync(operation, context, cancellationToken).ConfigureAwait(false));
     }
 }
        public static async Task <TResult> ExecuteAsync <TResult>(IRetryableReadOperation <TResult> operation, RetryableReadContext context, CancellationToken cancellationToken)
        {
            if (!ShouldReadBeRetried(context))
            {
                return(await operation.ExecuteAttemptAsync(context, attempt : 1, transactionNumber : null, cancellationToken).ConfigureAwait(false));
            }

            var       initialServerVersion = context.Channel.ConnectionDescription.ServerVersion;
            Exception originalException;

            try
            {
                return(await operation.ExecuteAttemptAsync(context, attempt : 1, transactionNumber : null, cancellationToken).ConfigureAwait(false));
            }
            catch (Exception ex) when(RetryabilityHelper.IsRetryableReadException(ex))
            {
                originalException = ex;
            }

            try
            {
                context.ReplaceChannelSource(context.Binding.GetReadChannelSource(cancellationToken));
                context.ReplaceChannel(context.ChannelSource.GetChannel(cancellationToken));
            }
            catch
            {
                throw originalException;
            }

            if (context.Channel.ConnectionDescription.ServerVersion < initialServerVersion)
            {
                throw originalException;
            }

            if (!AreRetryableReadsSupported(context))
            {
                throw originalException;
            }

            try
            {
                return(await operation.ExecuteAttemptAsync(context, attempt : 2, transactionNumber : null, cancellationToken).ConfigureAwait(false));
            }
            catch (Exception ex) when(ShouldThrowOriginalException(ex))
            {
                throw originalException;
            }
        }
        public static TResult Execute <TResult>(IRetryableReadOperation <TResult> operation, RetryableReadContext context, CancellationToken cancellationToken)
        {
            if (!ShouldReadBeRetried(context))
            {
                return(operation.ExecuteAttempt(context, attempt: 1, transactionNumber: null, cancellationToken));
            }

            Exception originalException;

            try
            {
                return(operation.ExecuteAttempt(context, attempt: 1, transactionNumber: null, cancellationToken));
            }
            catch (Exception ex) when(RetryabilityHelper.IsRetryableReadException(ex))
            {
                originalException = ex;
            }

            try
            {
                context.ReplaceChannelSource(context.Binding.GetReadChannelSource(cancellationToken));
                context.ReplaceChannel(context.ChannelSource.GetChannel(cancellationToken));
            }
            catch
            {
                throw originalException;
            }

            try
            {
                return(operation.ExecuteAttempt(context, attempt: 2, transactionNumber: null, cancellationToken));
            }
            catch (Exception ex) when(ShouldThrowOriginalException(ex))
            {
                throw originalException;
            }
        }