diff --git a/Vostok.ClusterClient.Core/IClusterClientConfigurationExtensions_Throttling.cs b/Vostok.ClusterClient.Core/IClusterClientConfigurationExtensions_Throttling.cs
index 8fcd829..3ec0a96 100644
--- a/Vostok.ClusterClient.Core/IClusterClientConfigurationExtensions_Throttling.cs
+++ b/Vostok.ClusterClient.Core/IClusterClientConfigurationExtensions_Throttling.cs
@@ -1,4 +1,6 @@
-using Vostok.Clusterclient.Core.Modules;
+using System.Collections.Generic;
+using Vostok.Clusterclient.Core.Model;
+using Vostok.Clusterclient.Core.Modules;
namespace Vostok.Clusterclient.Core
{
@@ -9,10 +11,10 @@ public static partial class IClusterClientConfigurationExtensions
///
/// A configuration to be modified.
/// See .
- /// See .
- /// See .
- /// See .
- /// See .
+ /// See .
+ /// See .
+ /// See .
+ /// See .
public static void SetupAdaptiveThrottling(
this IClusterClientConfiguration configuration,
string storageKey,
@@ -30,38 +32,16 @@ public static void SetupAdaptiveThrottling(
configuration.AddRequestModule(new AdaptiveThrottlingModule(options), typeof(AbsoluteUrlSenderModule));
}
-
- ///
- /// Sets up an adaptive client throttling mechanism with given parameters.
- ///
- /// A configuration to be modified.
- /// See .
- /// See .
- /// See .
- /// See .
- public static void SetupAdaptiveThrottling(
- this IClusterClientConfiguration configuration,
- string storageKey,
- AdaptiveThrottlingOptions criticalOptions,
- AdaptiveThrottlingOptions ordinaryOptions,
- AdaptiveThrottlingOptions sheddableOptions)
- {
- var defaultOptions = new AdaptiveThrottlingOptions(storageKey);
- criticalOptions ??= defaultOptions;
- ordinaryOptions ??= defaultOptions;
- sheddableOptions ??= defaultOptions;
- configuration.AddRequestModule(new AdaptiveThrottlingModule(storageKey, criticalOptions, ordinaryOptions, sheddableOptions), typeof(AbsoluteUrlSenderModule));
- }
///
/// Sets up an adaptive client throttling mechanism with given parameters using and as a storage key.
/// N.B. Ensure that and is set before calling this method.
///
/// A configuration to be modified.
- /// See .
- /// See .
- /// See .
- /// See .
+ /// See .
+ /// See .
+ /// See .
+ /// See .
public static void SetupAdaptiveThrottling(
this IClusterClientConfiguration configuration,
int minutesToTrack = ClusterClientDefaults.AdaptiveThrottlingMinutesToTrack,
@@ -73,25 +53,34 @@ public static void SetupAdaptiveThrottling(
SetupAdaptiveThrottling(configuration, storageKey, minutesToTrack, minimumRequests, criticalRatio, maximumRejectProbability);
}
-
+
///
- /// Sets up an adaptive client throttling mechanism with given parameters using and as a storage key.
- /// N.B. Ensure that and is set before calling this method.
+ /// Configures default settings by request priority for adaptive client throttling mechanism.
+ ///
+ public static AdaptiveThrottlingOptions ConfigureAdaptiveThrottlingOptions(string storageKey, AdaptiveThrottlingParameters defaultParameters)
+ {
+ defaultParameters ??= new AdaptiveThrottlingParameters();
+
+ var parameters = new Dictionary
+ {
+ [RequestPriority.Critical] = defaultParameters,
+ [RequestPriority.Ordinary] = defaultParameters,
+ [RequestPriority.Sheddable] = defaultParameters
+ };
+
+ return new AdaptiveThrottlingOptions(storageKey, parameters);
+ }
+
+ ///
+ /// Sets up an adaptive client throttling mechanism with given options.
///
/// A configuration to be modified.
- /// See .
- /// See .
- /// See .
- /// See .
+ /// See
public static void SetupAdaptiveThrottling(
this IClusterClientConfiguration configuration,
- AdaptiveThrottlingOptions criticalOptions,
- AdaptiveThrottlingOptions ordinaryOptions,
- AdaptiveThrottlingOptions sheddableOptions)
+ AdaptiveThrottlingOptions options)
{
- var storageKey = GenerateStorageKey(configuration);
-
- SetupAdaptiveThrottling(configuration, storageKey, criticalOptions, ordinaryOptions, sheddableOptions);
+ configuration.AddRequestModule(new AdaptiveThrottlingModule(options), typeof(AbsoluteUrlSenderModule));
}
}
}
\ No newline at end of file
diff --git a/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingModule.cs b/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingModule.cs
index 3b7f822..20f7e48 100644
--- a/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingModule.cs
+++ b/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingModule.cs
@@ -5,6 +5,7 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Vostok.Clusterclient.Core.Misc;
using Vostok.Clusterclient.Core.Model;
using Vostok.Commons.Threading;
using Vostok.Logging.Abstractions;
@@ -16,44 +17,16 @@ namespace Vostok.Clusterclient.Core.Modules
///
internal class AdaptiveThrottlingModule : IRequestModule
{
+ private static readonly RequestPriority DefaultPriority = RequestPriority.Sheddable;
private static readonly ConcurrentDictionary Counters = new();
private static readonly Stopwatch Watch = Stopwatch.StartNew();
private readonly Func counterFactory;
public AdaptiveThrottlingModule(AdaptiveThrottlingOptions options)
- : this(options.StorageKey, options, options, options)
{
- }
-
- public AdaptiveThrottlingModule(
- string storageKey,
- AdaptiveThrottlingOptions criticalOptions,
- AdaptiveThrottlingOptions ordinaryOptions,
- AdaptiveThrottlingOptions sheddableOptions)
- {
- StorageKey = storageKey;
- Options = new Dictionary
- {
- {RequestPriority.Critical, criticalOptions},
- {RequestPriority.Ordinary, ordinaryOptions},
- {RequestPriority.Sheddable, sheddableOptions}
- };
- counterFactory = _ => new CountersByPriority(
- criticalOptions.MinutesToTrack,
- ordinaryOptions.MinutesToTrack,
- sheddableOptions.MinutesToTrack
- );
- }
-
- public AdaptiveThrottlingModule(Dictionary options)
- {
- this.Options = options;
- counterFactory = _ => new CountersByPriority(
- options[RequestPriority.Critical].MinutesToTrack,
- options[RequestPriority.Ordinary].MinutesToTrack,
- options[RequestPriority.Sheddable].MinutesToTrack
- );
+ StorageKey = options.StorageKey;
+ counterFactory = _ => new CountersByPriority(options.Parameters);
}
public static void ClearCache()
@@ -61,22 +34,20 @@ public static void ClearCache()
Counters.Clear();
}
- public Dictionary Options { get; }
-
public int Requests(RequestPriority? priority) => GetCounter(priority).GetMetrics().Requests;
public int Accepts(RequestPriority? priority) => GetCounter(priority).GetMetrics().Accepts;
public double Ratio(RequestPriority? priority) => ComputeRatio(GetCounter(priority).GetMetrics());
- public double RejectionProbability(RequestPriority? priority) => ComputeRejectionProbability(GetCounter(priority).GetMetrics(), GetOptions(priority));
+ public double RejectionProbability(RequestPriority? priority) => ComputeRejectionProbability(GetCounter(priority).GetMetrics(), GetCounter(priority).Parameters);
public string StorageKey { get; }
public async Task ExecuteAsync(IRequestContext context, Func> next)
{
var counter = GetCounter(context.Parameters.Priority);
- var options = GetOptions(context.Parameters.Priority);
+ var options = counter.Parameters;
counter.BeginRequest();
ClusterResult result;
@@ -119,7 +90,7 @@ public async Task ExecuteAsync(IRequestContext context, Func
1.0 * metrics.Requests / Math.Max(1.0, metrics.Accepts);
- private static double ComputeRejectionProbability(CounterMetrics metrics, AdaptiveThrottlingOptions options)
+ private static double ComputeRejectionProbability(CounterMetrics metrics, AdaptiveThrottlingParameters options)
{
var probability = 1.0 * (metrics.Requests - options.CriticalRatio * metrics.Accepts) / (metrics.Requests + 1);
@@ -137,7 +108,7 @@ private static void UpdateCounter(Counter counter, ClusterResult result)
private Counter GetCounter(RequestPriority? priority)
{
- priority ??= RequestPriority.Sheddable;
+ priority ??= DefaultPriority;
var counters = Counters.GetOrAdd(StorageKey, counterFactory);
return priority switch
{
@@ -148,22 +119,24 @@ private Counter GetCounter(RequestPriority? priority)
};
}
- private AdaptiveThrottlingOptions GetOptions(RequestPriority? priority) => Options[priority ?? RequestPriority.Sheddable];
-
#region CountersByPriority
private class CountersByPriority
{
- public CountersByPriority(int criticalBuckets, int ordinaryBuckets, int sheddableBuckets)
+ private readonly Dictionary requestCounters;
+
+ public CountersByPriority(Dictionary options)
{
- CriticalRequestCounter = new Counter(criticalBuckets);
- OrdinaryRequestCounter = new Counter(ordinaryBuckets);
- SheddableRequestCounter = new Counter(sheddableBuckets);
+ requestCounters = new Dictionary();
+ foreach (var (priority, parameters) in options)
+ {
+ requestCounters[priority] = new Counter(parameters);
+ }
}
- public Counter CriticalRequestCounter { get; }
- public Counter OrdinaryRequestCounter { get; }
- public Counter SheddableRequestCounter { get; }
+ public Counter CriticalRequestCounter => requestCounters[RequestPriority.Critical];
+ public Counter OrdinaryRequestCounter => requestCounters[RequestPriority.Ordinary];
+ public Counter SheddableRequestCounter => requestCounters[RequestPriority.Sheddable];
}
#endregion
@@ -193,14 +166,19 @@ private class Counter
private readonly CounterBucket[] buckets;
private int pendingRequests;
- public Counter(int buckets)
+ public Counter(AdaptiveThrottlingParameters parameters)
{
- this.buckets = new CounterBucket[buckets];
+ Parameters = parameters;
+
+ var bucketsNumber = parameters.MinutesToTrack;
+ buckets = new CounterBucket[bucketsNumber];
- for (var i = 0; i < buckets; i++)
- this.buckets[i] = new CounterBucket();
+ for (var i = 0; i < bucketsNumber; i++)
+ buckets[i] = new CounterBucket();
}
+ public AdaptiveThrottlingParameters Parameters { get; }
+
public CounterMetrics GetMetrics()
{
var metrics = new CounterMetrics();
diff --git a/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingOptions.cs b/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingOptions.cs
index 7e84c73..83adeb7 100644
--- a/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingOptions.cs
+++ b/Vostok.ClusterClient.Core/Modules/AdaptiveThrottlingOptions.cs
@@ -1,5 +1,7 @@
using System;
+using System.Collections.Generic;
using JetBrains.Annotations;
+using Vostok.Clusterclient.Core.Model;
namespace Vostok.Clusterclient.Core.Modules
{
@@ -11,7 +13,7 @@ public class AdaptiveThrottlingOptions
{
/// A key used to decouple statistics for different services. This parameter is REQUIRED
/// How much minutes of statistics will be tracked. Must be >= 1.
- /// A minimum requests count in minutes to reject any request.
+ /// A minimum requests count in minutes to reject any request.
/// A minimum ratio of requests to accepts eligible for rejection. Must be > 1.
/// A cap on the request rejection probability to prevent eternal rejection.
/// is null.
@@ -23,9 +25,100 @@ public AdaptiveThrottlingOptions(
double criticalRatio = ClusterClientDefaults.AdaptiveThrottlingCriticalRatio,
double maximumRejectProbability = ClusterClientDefaults.AdaptiveThrottlingRejectProbabilityCap)
{
- if (storageKey == null)
- throw new ArgumentNullException(nameof(storageKey));
+ StorageKey = storageKey ?? throw new ArgumentNullException(nameof(storageKey));
+
+ var defaultParameters = new AdaptiveThrottlingParameters(
+ minutesToTrack,
+ minimumRequests,
+ criticalRatio,
+ maximumRejectProbability
+ );
+
+ Parameters = new Dictionary
+ {
+ [RequestPriority.Critical] = defaultParameters,
+ [RequestPriority.Ordinary] = defaultParameters,
+ [RequestPriority.Sheddable] = defaultParameters
+ };
+ }
+
+ /// A key used to decouple statistics for different services. This parameter is REQUIRED
+ /// A Dictionary in which provide adaptive throttling parameters by priority
+ /// is null.
+ public AdaptiveThrottlingOptions(
+ [NotNull] string storageKey,
+ Dictionary parameters)
+ {
+ StorageKey = storageKey ?? throw new ArgumentNullException(nameof(storageKey));
+
+ Parameters = parameters == null
+ ? new Dictionary()
+ : new Dictionary(parameters);
+
+ var defaultParameters = new AdaptiveThrottlingParameters();
+ if (!Parameters.ContainsKey(RequestPriority.Critical))
+ {
+ Parameters[RequestPriority.Critical] = defaultParameters;
+ }
+
+ if (!Parameters.ContainsKey(RequestPriority.Ordinary))
+ {
+ Parameters[RequestPriority.Ordinary] = defaultParameters;
+ }
+
+ if (!Parameters.ContainsKey(RequestPriority.Sheddable))
+ {
+ Parameters[RequestPriority.Sheddable] = defaultParameters;
+ }
+ StorageKey = storageKey;
+ }
+
+ ///
+ /// A key used to decouple statistics for different services.
+ ///
+ [NotNull]
+ public string StorageKey { get; }
+
+ ///
+ /// Dictionary in which stored adaptive throttling parameters by priority.
+ ///
+ public Dictionary Parameters { get; }
+
+ ///
+ /// Produces a new instance where adaptive throttling parameters by priority will have given value.
+ /// See class documentation for details.
+ ///
+ /// Priority name for details
+ /// Throttling parameters by priority.
+ /// A new object with updated throttling parameters for given priority.
+ public AdaptiveThrottlingOptions WithPriorityParameters(RequestPriority priority, AdaptiveThrottlingParameters criticalRequestParameters)
+ {
+ var parameters = new Dictionary(Parameters)
+ {
+ [RequestPriority.Critical] = criticalRequestParameters
+ };
+ return new AdaptiveThrottlingOptions(StorageKey, parameters);
+ }
+ }
+
+ ///
+ /// Represents a parameters of instance by request priority.
+ ///
+ [PublicAPI]
+ public class AdaptiveThrottlingParameters
+ {
+ /// How much minutes of statistics will be tracked. Must be >= 1.
+ /// A minimum requests count in minutes to reject any request.
+ /// A minimum ratio of requests to accepts eligible for rejection. Must be > 1.
+ /// A cap on the request rejection probability to prevent eternal rejection.
+ /// , or does not lie in expected range.
+ public AdaptiveThrottlingParameters(
+ int minutesToTrack = ClusterClientDefaults.AdaptiveThrottlingMinutesToTrack,
+ int minimumRequests = ClusterClientDefaults.AdaptiveThrottlingMinimumRequests,
+ double criticalRatio = ClusterClientDefaults.AdaptiveThrottlingCriticalRatio,
+ double maximumRejectProbability = ClusterClientDefaults.AdaptiveThrottlingRejectProbabilityCap)
+ {
if (minutesToTrack < 1)
throw new ArgumentOutOfRangeException(nameof(minutesToTrack), "Minutes to track parameter must be >= 1.");
@@ -35,19 +128,12 @@ public AdaptiveThrottlingOptions(
if (maximumRejectProbability < 0.0 || maximumRejectProbability > 1.0)
throw new ArgumentOutOfRangeException(nameof(maximumRejectProbability), "Maximum rejection probability must be in [0; 1] range.");
- StorageKey = storageKey;
MinutesToTrack = minutesToTrack;
MinimumRequests = minimumRequests;
CriticalRatio = criticalRatio;
MaximumRejectProbability = maximumRejectProbability;
}
- ///
- /// A key used to decouple statistics for different services.
- ///
- [NotNull]
- public string StorageKey { get; }
-
///
/// How much minutes of statistics will be tracked. Must be >= 1.
///
diff --git a/Vostok.ClusterClient.Core/PublicAPI.Unshipped.txt b/Vostok.ClusterClient.Core/PublicAPI.Unshipped.txt
index 573ed58..89e26f9 100644
--- a/Vostok.ClusterClient.Core/PublicAPI.Unshipped.txt
+++ b/Vostok.ClusterClient.Core/PublicAPI.Unshipped.txt
@@ -1,2 +1,15 @@
-static Vostok.Clusterclient.Core.IClusterClientConfigurationExtensions.SetupAdaptiveThrottling(this Vostok.Clusterclient.Core.IClusterClientConfiguration configuration, string storageKey, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions criticalOptions, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions ordinaryOptions, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions sheddableOptions) -> void
-static Vostok.Clusterclient.Core.IClusterClientConfigurationExtensions.SetupAdaptiveThrottling(this Vostok.Clusterclient.Core.IClusterClientConfiguration configuration, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions criticalOptions, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions ordinaryOptions, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions sheddableOptions) -> void
\ No newline at end of file
+static Vostok.Clusterclient.Core.IClusterClientConfigurationExtensions.ConfigureAdaptiveThrottlingOptions(string storageKey, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters defaultParameters) -> Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions
+static Vostok.Clusterclient.Core.IClusterClientConfigurationExtensions.SetupAdaptiveThrottling(this Vostok.Clusterclient.Core.IClusterClientConfiguration configuration, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions options) -> void
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.AdaptiveThrottlingOptions(string storageKey, System.Collections.Generic.Dictionary parameters) -> void
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.Parameters.get -> System.Collections.Generic.Dictionary
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.WithPriorityParameters(Vostok.Clusterclient.Core.Model.RequestPriority priority, Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters criticalRequestParameters) -> Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions
+*REMOVED*Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.MinutesToTrack.get -> int
+*REMOVED*Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.MinimumRequests.get -> int
+*REMOVED*Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.CriticalRatio.get -> double
+*REMOVED*Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingOptions.MaximumRejectProbability.get -> double
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters.AdaptiveThrottlingParameters(int minutesToTrack = 2, int minimumRequests = 30, double criticalRatio = 2, double maximumRejectProbability = 0.8) -> void
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters.CriticalRatio.get -> double
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters.MaximumRejectProbability.get -> double
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters.MinimumRequests.get -> int
+Vostok.Clusterclient.Core.Modules.AdaptiveThrottlingParameters.MinutesToTrack.get -> int
\ No newline at end of file