-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add retry policies into DPS device (#2926)
- Loading branch information
1 parent
5f1a2c5
commit 6448bff
Showing
22 changed files
with
770 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
provisioning/device/src/RetryPolicies/IProvisioningClientRetryPolicy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
|
||
namespace Microsoft.Azure.Devices.Provisioning.Client | ||
{ | ||
/// <summary> | ||
/// Represents a retry policy for the DPS device client. | ||
/// </summary> | ||
public interface IProvisioningClientRetryPolicy | ||
{ | ||
/// <summary> | ||
/// Method called by the client prior to a retry. | ||
/// </summary> | ||
/// <param name="currentRetryCount">The number of times the current operation has been attempted.</param> | ||
/// <param name="lastException">The exception that caused this retry policy check.</param> | ||
/// <param name="retryDelay">Set this to the desired delay prior to the next attempt.</param> | ||
/// <returns>True if the operation should be retried, otherwise false.</returns> | ||
bool ShouldRetry(uint currentRetryCount, Exception lastException, out TimeSpan retryDelay); | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
provisioning/device/src/RetryPolicies/ProvisioningClientExponentialBackoffRetryPolicy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
|
||
namespace Microsoft.Azure.Devices.Provisioning.Client | ||
{ | ||
/// <summary> | ||
/// Represents a retry policy that performs a specified number of retries, using a exponential back-off scheme, with option jitter, | ||
/// to determine the interval between retries. | ||
/// </summary> | ||
/// <remarks> | ||
/// Jitter can change the delay from 95% to 105% of the calculated time. | ||
/// </remarks> | ||
public class ProvisioningClientExponentialBackoffRetryPolicy : ProvisioningClientRetryPolicyBase | ||
{ | ||
// If we start with an exponent of 1 to calculate the number of millisecond delay, it starts too low and takes too long to get over 1 second. | ||
// So we always add 6 to the retry count to start at 2^7=128 milliseconds, and exceed 1 second delay on retry #4. | ||
private const uint MinExponent = 6u; | ||
|
||
// Avoid integer overlow (max of 32) and clamp max delay. | ||
private const uint MaxExponent = 32u; | ||
|
||
private readonly TimeSpan _maxDelay; | ||
private readonly bool _useJitter; | ||
|
||
/// <summary> | ||
/// Creates an instance of this class. | ||
/// </summary> | ||
/// <param name="maxRetries">The maximum number of retry attempts; use 0 for infinite retries.</param> | ||
/// <param name="maxWait">The maximum amount of time to wait between retries (will not exceed ~12.43 days).</param> | ||
/// <param name="useJitter">Whether to add a small, random adjustment to the retry delay to avoid synchronicity in clients retrying.</param> | ||
/// <exception cref="ArgumentOutOfRangeException">Throw if the value of <paramref name="maxWait"/> is negative.</exception> | ||
public ProvisioningClientExponentialBackoffRetryPolicy(uint maxRetries, TimeSpan maxWait, bool useJitter = true) | ||
: base(maxRetries) | ||
{ | ||
Argument.AssertNotNegativeValue(maxWait, nameof(maxWait)); | ||
|
||
_maxDelay = maxWait; | ||
_useJitter = useJitter; | ||
} | ||
|
||
/// <summary> | ||
/// Returns true if, based on the parameters, the operation should be retried. | ||
/// </summary> | ||
/// <param name="currentRetryCount">How many times the operation has been retried.</param> | ||
/// <param name="lastException">Operation exception.</param> | ||
/// <param name="retryInterval">Next retry should be performed after this time interval.</param> | ||
/// <returns>True if the operation should be retried, false otherwise.</returns> | ||
public override bool ShouldRetry(uint currentRetryCount, Exception lastException, out TimeSpan retryInterval) | ||
{ | ||
if (!base.ShouldRetry(currentRetryCount, lastException, out retryInterval)) | ||
{ | ||
return false; | ||
} | ||
|
||
// Avoid integer overlow and clamp max delay. | ||
uint exponent = currentRetryCount + MinExponent; | ||
exponent = Math.Min(MaxExponent, exponent); | ||
|
||
// 2 to the power of the retry count gives us exponential back-off. | ||
double exponentialIntervalMs = Math.Pow(2.0, exponent); | ||
|
||
double clampedWaitMs = Math.Min(exponentialIntervalMs, _maxDelay.TotalMilliseconds); | ||
|
||
retryInterval = _useJitter | ||
? UpdateWithJitter(clampedWaitMs) | ||
: TimeSpan.FromMilliseconds(clampedWaitMs); | ||
|
||
return true; | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
provisioning/device/src/RetryPolicies/ProvisioningClientFixedDelayRetryPolicy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
|
||
namespace Microsoft.Azure.Devices.Provisioning.Client | ||
{ | ||
/// <summary> | ||
/// Represents a retry policy that performs a specified number of retries, using a fixed retry delay with jitter. | ||
/// </summary> | ||
/// <remarks> | ||
/// Jitter can change the delay from 95% to 105% of the calculated time. | ||
/// </remarks> | ||
public class ProvisioningClientFixedDelayRetryPolicy : ProvisioningClientRetryPolicyBase | ||
{ | ||
private readonly TimeSpan _fixedDelay; | ||
private readonly bool _useJitter; | ||
|
||
/// <summary> | ||
/// Creates an instance of this class. | ||
/// </summary> | ||
/// <param name="maxRetries">The maximum number of retry attempts; use 0 for infinite retries.</param> | ||
/// <param name="fixedDelay">The fixed delay to wait between retries.</param> | ||
/// <param name="useJitter">Whether to add a small, random adjustment to the retry delay to avoid synchronicity in retrying clients.</param> | ||
/// <exception cref="ArgumentOutOfRangeException">Throw if the value of <paramref name="fixedDelay"/> is negative.</exception> | ||
public ProvisioningClientFixedDelayRetryPolicy(uint maxRetries, TimeSpan fixedDelay, bool useJitter = true) | ||
: base(maxRetries) | ||
{ | ||
Argument.AssertNotNegativeValue(fixedDelay, nameof(fixedDelay)); | ||
|
||
_fixedDelay = fixedDelay; | ||
_useJitter = useJitter; | ||
} | ||
|
||
/// <summary> | ||
/// Returns true if, based on the parameters, the operation should be retried. | ||
/// </summary> | ||
/// <param name="currentRetryCount">How many times the operation has been retried.</param> | ||
/// <param name="lastException">Operation exception.</param> | ||
/// <param name="retryInterval">Next retry should be performed after this time interval.</param> | ||
/// <returns>True if the operation should be retried, false otherwise.</returns> | ||
public override bool ShouldRetry(uint currentRetryCount, Exception lastException, out TimeSpan retryInterval) | ||
{ | ||
if (!base.ShouldRetry(currentRetryCount, lastException, out retryInterval)) | ||
{ | ||
return false; | ||
} | ||
|
||
retryInterval = _useJitter | ||
? UpdateWithJitter(_fixedDelay.TotalMilliseconds) | ||
: _fixedDelay; | ||
|
||
return true; | ||
} | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
provisioning/device/src/RetryPolicies/ProvisioningClientIncrementalDelayRetryPolicy.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
|
||
namespace Microsoft.Azure.Devices.Provisioning.Client | ||
{ | ||
/// <summary> | ||
/// Represents a retry policy that performs a specified number of retries, using an incrementally increasing retry delay with jitter. | ||
/// </summary> | ||
/// <remarks> | ||
/// Jitter can change the delay from 95% to 105% of the calculated time. | ||
/// </remarks> | ||
public class ProvisioningClientIncrementalDelayRetryPolicy : ProvisioningClientRetryPolicyBase | ||
{ | ||
/// <summary> | ||
/// Creates an instance of this class. | ||
/// </summary> | ||
/// <param name="maxRetries">The maximum number of retry attempts; use 0 for infinite retries.</param> | ||
/// <param name="delayIncrement">The amount to increment the delay on each additional count of retry.</param> | ||
/// <param name="maxDelay">The maximum amount of time to wait between retries.</param> | ||
/// <param name="useJitter">Whether to add a small, random adjustment to the retry delay to avoid synchronicity in clients retrying.</param> | ||
/// <exception cref="ArgumentOutOfRangeException"> | ||
/// Throw if the value of <paramref name="delayIncrement"/> or <paramref name="maxDelay"/> is negative. | ||
/// </exception> | ||
public ProvisioningClientIncrementalDelayRetryPolicy(uint maxRetries, TimeSpan delayIncrement, TimeSpan maxDelay, bool useJitter = true) | ||
: base(maxRetries) | ||
{ | ||
Argument.AssertNotNegativeValue(delayIncrement, nameof(delayIncrement)); | ||
Argument.AssertNotNegativeValue(maxDelay, nameof(maxDelay)); | ||
|
||
DelayIncrement = delayIncrement; | ||
MaxDelay = maxDelay; | ||
UseJitter = useJitter; | ||
} | ||
|
||
/// <summary> | ||
/// The amount to increment the delay on each additional count of retry. | ||
/// </summary> | ||
internal protected TimeSpan DelayIncrement { get; } | ||
|
||
/// <summary> | ||
/// The maximum amount of time to wait between retries. | ||
/// </summary> | ||
internal protected TimeSpan MaxDelay { get; } | ||
|
||
/// <summary> | ||
/// Whether to add a small, random adjustment to the retry delay to avoid synchronicity in clients retrying. | ||
/// </summary> | ||
internal protected bool UseJitter { get; } | ||
|
||
/// <summary> | ||
/// Returns true if, based on the parameters, the operation should be retried. | ||
/// </summary> | ||
/// <param name="currentRetryCount">How many times the operation has been retried.</param> | ||
/// <param name="lastException">Operation exception.</param> | ||
/// <param name="retryInterval">Next retry should be performed after this time interval.</param> | ||
/// <returns>True if the operation should be retried, false otherwise.</returns> | ||
public override bool ShouldRetry(uint currentRetryCount, Exception lastException, out TimeSpan retryInterval) | ||
{ | ||
if (!base.ShouldRetry(currentRetryCount, lastException, out retryInterval)) | ||
{ | ||
return false; | ||
} | ||
|
||
double waitDurationMs = Math.Min( | ||
currentRetryCount * DelayIncrement.TotalMilliseconds, | ||
MaxDelay.TotalMilliseconds); | ||
|
||
retryInterval = UseJitter | ||
? UpdateWithJitter(waitDurationMs) | ||
: TimeSpan.FromMilliseconds(waitDurationMs); | ||
|
||
return true; | ||
} | ||
} | ||
} |
Oops, something went wrong.