| | 1 | | // Copyright (c) Microsoft Corporation. All rights reserved. |
| | 2 | | // Licensed under the MIT License. See License.txt in the project root for license information. |
| | 3 | |
|
| | 4 | | namespace Microsoft.Azure.Batch.Common |
| | 5 | | { |
| | 6 | | using System; |
| | 7 | | using System.Threading.Tasks; |
| | 8 | |
|
| | 9 | | /// <summary> |
| | 10 | | /// Represents a retry policy that performs a specified number of retries, using an exponential backoff scheme to de |
| | 11 | | /// </summary> |
| | 12 | | public class ExponentialRetry : IRetryPolicy |
| | 13 | | { |
| | 14 | | /// <summary> |
| | 15 | | /// Gets the backoff interval between retries, where the resulting backoff is 2^n * deltaBackoff (where n is the |
| | 16 | | /// </summary> |
| 677 | 17 | | public TimeSpan DeltaBackoff { get; private set; } |
| | 18 | |
|
| | 19 | | /// <summary> |
| | 20 | | /// Gets the maximum number of retry attempts. |
| | 21 | | /// </summary> |
| 682 | 22 | | public int MaximumRetries { get; private set; } |
| | 23 | |
|
| | 24 | | /// <summary> |
| | 25 | | /// The maximum duration to wait between retries. |
| | 26 | | /// </summary> |
| 683 | 27 | | public TimeSpan? MaxBackoff { get; private set; } |
| | 28 | |
|
| | 29 | | /// <summary> |
| | 30 | | /// Initializes a new instance of the <see cref="ExponentialRetry"/> class using the specified delta and maximum |
| | 31 | | /// </summary> |
| | 32 | | /// <param name="deltaBackoff">The backoff interval between retries, where the resulting backoff is 2^n * deltaB |
| | 33 | | /// <param name="maxRetries">The maximum number of retry attempts.</param> |
| | 34 | | /// <param name="maxBackoff">The maximum duration to wait between retries.</param> |
| 665 | 35 | | public ExponentialRetry(TimeSpan deltaBackoff, int maxRetries, TimeSpan? maxBackoff = null) |
| | 36 | | { |
| 665 | 37 | | RetryPolicyCommon.ValidateArguments(deltaBackoff, maxRetries); |
| | 38 | |
|
| 663 | 39 | | if (maxBackoff < TimeSpan.Zero) |
| | 40 | | { |
| 0 | 41 | | throw new ArgumentOutOfRangeException(nameof(maxBackoff)); |
| | 42 | | } |
| | 43 | |
|
| 663 | 44 | | this.DeltaBackoff = deltaBackoff; |
| 663 | 45 | | this.MaximumRetries = maxRetries; |
| 663 | 46 | | this.MaxBackoff = maxBackoff; |
| 663 | 47 | | } |
| | 48 | |
|
| | 49 | | /// <summary> |
| | 50 | | /// Determines if the operation should be retried and how long to wait until the next retry. |
| | 51 | | /// </summary> |
| | 52 | | /// <param name="exception">An <see cref="Exception"/> object that represents the last exception encountered.</p |
| | 53 | | /// <param name="operationContext">An <see cref="OperationContext"/> object for tracking the current operation.< |
| | 54 | | /// <returns>A <see cref="RetryDecision"/> object which specifies if a retry should be performed.</returns> |
| | 55 | | public Task<RetryDecision> ShouldRetryAsync(Exception exception, OperationContext operationContext) |
| | 56 | | { |
| 26 | 57 | | if (operationContext == null) |
| | 58 | | { |
| 0 | 59 | | throw new ArgumentNullException("operationContext"); |
| | 60 | | } |
| | 61 | |
|
| 26 | 62 | | bool shouldRetry = RetryPolicyCommon.ShouldRetry(exception, operationContext, this.MaximumRetries); |
| 26 | 63 | | TimeSpan? retryAfter = (exception as BatchException)?.RequestInformation?.RetryAfter; |
| 26 | 64 | | int currentRetryCount = operationContext.RequestResults.Count - 1; |
| | 65 | |
|
| | 66 | | RetryDecision decision; |
| 26 | 67 | | if (shouldRetry) |
| | 68 | | { |
| 21 | 69 | | double deltaBackoffMilliseconds = this.DeltaBackoff.TotalMilliseconds; |
| 21 | 70 | | double millisecondsBackoff = Math.Pow(2, currentRetryCount) * deltaBackoffMilliseconds; |
| | 71 | |
|
| 21 | 72 | | var delay = TimeSpan.FromMilliseconds(millisecondsBackoff); |
| 21 | 73 | | delay = retryAfter.HasValue && delay > retryAfter ? retryAfter.Value : delay; |
| 21 | 74 | | delay = this.MaxBackoff.HasValue && delay > this.MaxBackoff ? this.MaxBackoff.Value : delay; |
| | 75 | |
|
| 21 | 76 | | decision = RetryDecision.RetryWithDelay(delay); |
| | 77 | | } |
| | 78 | | else |
| | 79 | | { |
| 5 | 80 | | decision = RetryDecision.NoRetry; |
| | 81 | | } |
| | 82 | |
|
| 26 | 83 | | return Task.FromResult(decision); |
| | 84 | | } |
| | 85 | | } |
| | 86 | | } |