< Summary

Class:Azure.Messaging.ServiceBus.Core.BasicRetryPolicy
Assembly:Azure.Messaging.ServiceBus
File(s):C:\Git\azure-sdk-for-net\sdk\servicebus\Azure.Messaging.ServiceBus\src\Core\BasicRetryPolicy.cs
Covered lines:30
Uncovered lines:7
Coverable lines:37
Total lines:185
Line coverage:81% (30 of 37)
Covered branches:25
Total branches:36
Branch coverage:69.4% (25 of 36)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
get_Options()-100%100%
get_JitterFactor()-100%100%
.ctor(...)-100%100%
CalculateTryTimeout(...)-100%100%
CalculateRetryDelay(...)-81.25%75%
ShouldRetryException(...)-70%65%
CalculateExponentialDelay(...)-0%100%
CalculateFixedDelay(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\servicebus\Azure.Messaging.ServiceBus\src\Core\BasicRetryPolicy.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System;
 5using System.Globalization;
 6using System.Net.Sockets;
 7using System.Threading;
 8using System.Threading.Tasks;
 9using System.Transactions;
 10using Azure.Core;
 11
 12namespace Azure.Messaging.ServiceBus.Core
 13{
 14    /// <summary>
 15    ///   The default retry policy for the Service Bus client library, respecting the
 16    ///   configuration specified as a set of <see cref="ServiceBusRetryOptions" />.
 17    /// </summary>
 18    ///
 19    /// <seealso cref="ServiceBusRetryOptions"/>
 20    ///
 21    internal class BasicRetryPolicy : ServiceBusRetryPolicy
 22    {
 23        /// <summary>The seed to use for initializing random number generated for a given thread-specific instance.</sum
 224        private static int s_randomSeed = Environment.TickCount;
 25
 26        /// <summary>The random number generator to use for a specific thread.</summary>
 1627        private static readonly ThreadLocal<Random> RandomNumberGenerator = new ThreadLocal<Random>(() => new Random(Int
 28
 29        /// <summary>
 30        ///   The set of options responsible for configuring the retry
 31        ///   behavior.
 32        /// </summary>
 33        ///
 23434        public ServiceBusRetryOptions Options { get; }
 35
 36        /// <summary>
 37        ///   The factor to apply to the base delay for use as a base jitter value.
 38        /// </summary>
 39        ///
 40        /// <value>This factor is used as the basis for random jitter to apply to the calculated retry duration.</value>
 41        ///
 12442        public double JitterFactor { get; } = 0.08;
 43
 44        /// <summary>
 45        ///   Initializes a new instance of the <see cref="BasicRetryPolicy"/> class.
 46        /// </summary>
 47        ///
 48        /// <param name="retryOptions">The options which control the retry approach.</param>
 49        ///
 10650        public BasicRetryPolicy(ServiceBusRetryOptions retryOptions)
 51        {
 10652            Argument.AssertNotNull(retryOptions, nameof(retryOptions));
 10653            Options = retryOptions;
 10654        }
 55
 56        /// <summary>
 57        ///   Calculates the amount of time to allow the current attempt for an operation to
 58        ///   complete before considering it to be timed out.
 59        /// </summary>
 60        ///
 61        /// <param name="attemptCount">The number of total attempts that have been made, including the initial attempt b
 62        ///
 63        /// <returns>The amount of time to allow for an operation to complete.</returns>
 64        ///
 3665        public override TimeSpan CalculateTryTimeout(int attemptCount) => Options.TryTimeout;
 66
 67        /// <summary>
 68        ///   Calculates the amount of time to wait before another attempt should be made.
 69        /// </summary>
 70        ///
 71        /// <param name="lastException">The last exception that was observed for the operation to be retried.</param>
 72        /// <param name="attemptCount">The number of total attempts that have been made, including the initial attempt b
 73        ///
 74        /// <returns>The amount of time to delay before retrying the associated operation; if <c>null</c>, then the oper
 75        ///
 76        public override TimeSpan? CalculateRetryDelay(
 77            Exception lastException,
 78            int attemptCount)
 79        {
 3680            if ((Options.MaxRetries <= 0)
 3681                || (Options.Delay == TimeSpan.Zero)
 3682                || (Options.MaxDelay == TimeSpan.Zero)
 3683                || (attemptCount > Options.MaxRetries)
 3684                || (!ShouldRetryException(lastException)))
 85            {
 1886                return null;
 87            }
 88
 1889            var baseJitterSeconds = (Options.Delay.TotalSeconds * JitterFactor);
 90
 1891            TimeSpan retryDelay = Options.Mode switch
 1892            {
 3693                ServiceBusRetryMode.Fixed => CalculateFixedDelay(Options.Delay.TotalSeconds, baseJitterSeconds, RandomNu
 094                ServiceBusRetryMode.Exponential => CalculateExponentialDelay(attemptCount, Options.Delay.TotalSeconds, b
 095                _ => throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, Resources.UnknownRetryMod
 1896            };
 97
 98            // Adjust the delay, if needed, to keep within the maximum
 99            // duration.
 100
 18101            if (Options.MaxDelay < retryDelay)
 102            {
 0103                return Options.MaxDelay;
 104            }
 105
 18106            return retryDelay;
 107        }
 108
 109        /// <summary>
 110        ///   Determines if an exception should be retried.
 111        /// </summary>
 112        ///
 113        /// <param name="exception">The exception to consider.</param>
 114        ///
 115        /// <returns><c>true</c> to retry the exception; otherwise, <c>false</c>.</returns>
 116        ///
 117        private static bool ShouldRetryException(Exception exception)
 118        {
 119            // There's there's an ambient transaction - should not retry
 24120            if (Transaction.Current != null)
 121            {
 0122                return false;
 123            }
 124
 24125            if ((exception is TaskCanceledException) || (exception is OperationCanceledException))
 126            {
 2127                exception = exception?.InnerException;
 128            }
 22129            else if (exception is AggregateException aggregateEx)
 130            {
 0131                exception = aggregateEx?.Flatten().InnerException;
 132            }
 133
 134            switch (exception)
 135            {
 136                case null:
 2137                    return false;
 138
 139                case ServiceBusException ex:
 18140                    return ex.IsTransient;
 141
 142                case TimeoutException _:
 143                case SocketException _:
 0144                    return true;
 145
 146                default:
 4147                    return false;
 148            }
 149        }
 150
 151        /// <summary>
 152        ///   Calculates the delay for an exponential back-off.
 153        /// </summary>
 154        ///
 155        /// <param name="attemptCount">The number of total attempts that have been made, including the initial attempt b
 156        /// <param name="baseDelaySeconds">The delay to use as a basis for the exponential back-off, in seconds.</param>
 157        /// <param name="baseJitterSeconds">The delay to use as the basis for a random jitter value, in seconds.</param>
 158        /// <param name="random">The random number generator to use for the calculation.</param>
 159        ///
 160        /// <returns>The recommended duration to delay before retrying; this value does not take the maximum delay or el
 161        ///
 162        private static TimeSpan CalculateExponentialDelay(
 163            int attemptCount,
 164            double baseDelaySeconds,
 165            double baseJitterSeconds,
 166            Random random) =>
 0167            TimeSpan.FromSeconds((Math.Pow(2, attemptCount) * baseDelaySeconds) + (random.NextDouble() * baseJitterSecon
 168
 169        /// <summary>
 170        ///   Calculates the delay for a fixed back-off.
 171        /// </summary>
 172        ///
 173        /// <param name="baseDelaySeconds">The delay to use as a basis for the fixed back-off, in seconds.</param>
 174        /// <param name="baseJitterSeconds">The delay to use as the basis for a random jitter value, in seconds.</param>
 175        /// <param name="random">The random number generator to use for the calculation.</param>
 176        ///
 177        /// <returns>The recommended duration to delay before retrying; this value does not take the maximum delay or el
 178        ///
 179        private static TimeSpan CalculateFixedDelay(
 180            double baseDelaySeconds,
 181            double baseJitterSeconds,
 182            Random random) =>
 18183            TimeSpan.FromSeconds(baseDelaySeconds + (random.NextDouble() * baseJitterSeconds));
 184    }
 185}