Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
576 changes: 288 additions & 288 deletions FiftyOne.Pipeline.CloudRequestEngine/FlowElements/CloudRequestEngine.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
* ********************************************************************* */

using FiftyOne.Pipeline.CloudRequestEngine.Data;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Facade;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Recovery;
using FiftyOne.Pipeline.Core.FailHandling.Facade;
using FiftyOne.Pipeline.Core.FailHandling.Recovery;
using FiftyOne.Pipeline.Core.Attributes;
using FiftyOne.Pipeline.Core.Exceptions;
using FiftyOne.Pipeline.Core.FlowElements;
Expand Down Expand Up @@ -63,6 +63,10 @@ public class CloudRequestEngineBuilder :
private int _failuresToEnterRecovery = Constants.CLOUD_REQUEST_FAILURES_TO_ENTER_RECOVERY_DEFAULT;
private int _failuresWindowSeconds = Constants.CLOUD_REQUEST_FAILURES_WINDOW_SECONDS_DEFAULT;
private double _recoverySeconds = Constants.CLOUD_REQUEST_RECOVERY_SECONDS_DEFAULT;
private bool _useExponentialBackoff = false;
private double _exponentialBackoffInitialDelay = ExponentialBackoffRecoveryStrategy.INITIAL_DELAY_SECONDS_DEFAULT;
private double _exponentialBackoffMaxDelay = ExponentialBackoffRecoveryStrategy.MAX_DELAY_SECONDS_DEFAULT;
private double _exponentialBackoffMultiplier = ExponentialBackoffRecoveryStrategy.MULTIPLIER_DEFAULT;

#endregion

Expand Down Expand Up @@ -249,6 +253,57 @@ public CloudRequestEngineBuilder SetRecoverySeconds(double recoverySeconds)
return this;
}

/// <summary>
/// Enable exponential backoff recovery strategy instead of simple recovery.
/// </summary>
/// <param name="useExponentialBackoff">True to use exponential backoff, false for simple recovery</param>
/// <returns>This builder instance</returns>
[DefaultValue(false)]
public CloudRequestEngineBuilder SetUseExponentialBackoff(bool useExponentialBackoff)
{
_useExponentialBackoff = useExponentialBackoff;
return this;
}

/// <summary>
/// Set the initial delay in seconds for exponential backoff recovery strategy.
/// Only used when exponential backoff is enabled.
/// </summary>
/// <param name="initialDelaySeconds">Initial delay in seconds</param>
/// <returns>This builder instance</returns>
[DefaultValue(ExponentialBackoffRecoveryStrategy.INITIAL_DELAY_SECONDS_DEFAULT)]
public CloudRequestEngineBuilder SetExponentialBackoffInitialDelay(double initialDelaySeconds)
{
_exponentialBackoffInitialDelay = initialDelaySeconds;
return this;
}

/// <summary>
/// Set the maximum delay in seconds for exponential backoff recovery strategy.
/// Only used when exponential backoff is enabled.
/// </summary>
/// <param name="maxDelaySeconds">Maximum delay in seconds</param>
/// <returns>This builder instance</returns>
[DefaultValue(ExponentialBackoffRecoveryStrategy.MAX_DELAY_SECONDS_DEFAULT)]
public CloudRequestEngineBuilder SetExponentialBackoffMaxDelay(double maxDelaySeconds)
{
_exponentialBackoffMaxDelay = maxDelaySeconds;
return this;
}

/// <summary>
/// Set the multiplier for exponential backoff recovery strategy.
/// Only used when exponential backoff is enabled.
/// </summary>
/// <param name="multiplier">Exponential multiplier (typically 2.0 for doubling)</param>
/// <returns>This builder instance</returns>
[DefaultValue(ExponentialBackoffRecoveryStrategy.MULTIPLIER_DEFAULT)]
public CloudRequestEngineBuilder SetExponentialBackoffMultiplier(double multiplier)
{
_exponentialBackoffMultiplier = multiplier;
return this;
}

/// <summary>
/// The value to set for the Origin header when making requests
/// to the cloud service.
Expand Down Expand Up @@ -314,6 +369,20 @@ private CloudRequestData CreateAspectData(IPipeline pipeline,
(IAspectEngine)engine);
}

/// <summary>
/// Create the appropriate recovery strategy based on current configuration.
/// </summary>
/// <returns>The configured recovery strategy</returns>
private IRecoveryStrategy CreateRecoveryStrategy()
{
return RecoveryStrategyFactory.Create(
_useExponentialBackoff,
_recoverySeconds,
_exponentialBackoffInitialDelay,
_exponentialBackoffMaxDelay,
_exponentialBackoffMultiplier);
}

/// <summary>
/// Create a new engine using the current configuration.
/// </summary>
Expand All @@ -331,10 +400,7 @@ protected override CloudRequestEngine NewEngine(List<string> properties)
Messages.ExceptionResourceKeyNeeded);
}

var failThrottlingStrategy
= (_recoverySeconds > 0)
? new SimpleRecoveryStrategy(_recoverySeconds)
: (IRecoveryStrategy)new InstantRecoveryStrategy();
var failThrottlingStrategy = CreateRecoveryStrategy();

return new CloudRequestEngine(
_loggerFactory.CreateLogger<CloudRequestEngine>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
using System.Collections.Generic;
using System.Text;

namespace FiftyOne.Pipeline.CloudRequestEngine.FailHandling.ExceptionCaching
namespace FiftyOne.Pipeline.Core.FailHandling.ExceptionCaching
{
/// <summary>
/// Links the exception and the timestamp.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Scope;
using FiftyOne.Pipeline.Core.Exceptions;
using FiftyOne.Pipeline.Core.FailHandling.Scope;
using System;
using System.Collections.Generic;
using System.Text;

namespace FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Facade
namespace FiftyOne.Pipeline.Core.FailHandling.Facade
{
/// <summary>
/// Tracks failures and throttles requests.
Expand All @@ -36,10 +37,19 @@ public interface IFailHandler
/// Throws if the strategy indicates that
/// requests may not be sent now.
/// </summary>
/// <exception cref="CloudRequestEngineTemporarilyUnavailableException">
/// <exception cref="PipelineTemporarilyUnavailableException">
/// </exception>
void ThrowIfStillRecovering();

/// <summary>
/// Checks if requests may be sent now without throwing exceptions.
/// Use this for non-critical operations that should silently skip when unavailable.
/// </summary>
/// <returns>
/// True if requests may be sent, false if still in recovery mode.
/// </returns>
bool IsAvailable();

/// <summary>
/// Lets a consumer to wrap an attempt in `using` scope
/// to implicitly report success
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.ExceptionCaching;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Recovery;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Scope;
using FiftyOne.Pipeline.Core.Exceptions;
using FiftyOne.Pipeline.Core.FailHandling.ExceptionCaching;
using FiftyOne.Pipeline.Core.FailHandling.Recovery;
using FiftyOne.Pipeline.Core.FailHandling.Scope;
using System;
using System.Collections.Generic;
using System.Text;

namespace FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Facade
namespace FiftyOne.Pipeline.Core.FailHandling.Facade
{
/// <summary>
/// Tracks failures and throttles requests.
Expand All @@ -52,18 +53,30 @@ public SimpleFailHandler(IRecoveryStrategy recoveryStrategy)
/// Throws if the strategy indicates that
/// requests may not be sent now.
/// </summary>
/// <exception cref="CloudRequestEngineTemporarilyUnavailableException">
/// <exception cref="PipelineTemporarilyUnavailableException">
/// </exception>
public void ThrowIfStillRecovering()
{
if (!_recoveryStrategy.MayTryNow(out var cachedException))
{
throw new Exception(
throw new PipelineTemporarilyUnavailableException(
$"Recovered exception from {(DateTime.Now - cachedException.DateTime).TotalSeconds}s ago.",
cachedException.Exception);
}
}

/// <summary>
/// Checks if requests may be sent now without throwing exceptions.
/// Use this for non-critical operations that should silently skip when unavailable.
/// </summary>
/// <returns>
/// True if requests may be sent, false if still in recovery mode.
/// </returns>
public bool IsAvailable()
{
return _recoveryStrategy.MayTryNow(out var _);
}

/// <summary>
/// Lets a consumer to wrap an attempt in `using` scope
/// to implicitly report success
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
* such notice(s) shall fulfill the requirements of that article.
* ********************************************************************* */

using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.ExceptionCaching;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Recovery;
using FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Scope;
using FiftyOne.Pipeline.Core.Exceptions;
using FiftyOne.Pipeline.Core.FailHandling.ExceptionCaching;
using FiftyOne.Pipeline.Core.FailHandling.Recovery;
using FiftyOne.Pipeline.Core.FailHandling.Scope;
using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace FiftyOne.Pipeline.CloudRequestEngine.FailHandling.Facade
namespace FiftyOne.Pipeline.Core.FailHandling.Facade
{
/// <summary>
/// Tracks failures and throttles requests.
Expand Down Expand Up @@ -149,7 +150,7 @@ public WindowedFailHandler(
/// Throws if the strategy indicates that
/// requests may not be sent now.
/// </summary>
/// <exception cref="CloudRequestEngineTemporarilyUnavailableException">
/// <exception cref="PipelineTemporarilyUnavailableException">
/// </exception>
public void ThrowIfStillRecovering()
{
Expand Down Expand Up @@ -201,7 +202,7 @@ public void ThrowIfStillRecovering()
break;
}
}
throw new Exception(
throw new PipelineTemporarilyUnavailableException(
$"Recovered exception from {(DateTime.Now - cachedException.DateTime).TotalSeconds}s ago.",
cachedException.Exception);
}
Expand Down Expand Up @@ -235,6 +236,18 @@ public void ThrowIfStillRecovering()
}
}

/// <summary>
/// Checks if requests may be sent now without throwing exceptions.
/// Use this for non-critical operations that should silently skip when unavailable.
/// </summary>
/// <returns>
/// True if requests may be sent, false if still in recovery mode.
/// </returns>
public bool IsAvailable()
{
return _recoveryStrategy.MayTryNow(out var _);
}

/// <summary>
/// Lets a consumer to wrap an attempt in `using` scope
/// to implicitly report success
Expand Down
Loading