3 namespace Hammock.Tasks
8 public class RateLimitingRule<T> : IRateLimitingRule<T>
10 private readonly RateLimitType _rateLimitType;
12 public RateLimitingRule(Predicate<T> rateLimitIf)
14 _rateLimitType = RateLimitType.ByPredicate;
15 RateLimitIf = rateLimitIf;
18 public RateLimitingRule(double percentOfTotal)
20 _rateLimitType = RateLimitType.ByPercent;
21 LimitToPercentOfTotal = percentOfTotal;
24 public RateLimitingRule(Func<T> getRateLimitStatus, Predicate<T> rateLimitIf)
26 _rateLimitType = RateLimitType.ByPredicate;
27 GetRateLimitStatus = getRateLimitStatus;
28 RateLimitIf = rateLimitIf;
31 public RateLimitingRule(Func<T> getRateLimitStatus, double percentOfTotal)
33 _rateLimitType = RateLimitType.ByPercent;
34 GetRateLimitStatus = getRateLimitStatus;
35 LimitToPercentOfTotal = percentOfTotal;
38 #region IRateLimitingRule Members
40 public virtual double? LimitToPercentOfTotal { get; private set; }
41 public virtual RateLimitType RateLimitType
43 get { return _rateLimitType; }
46 public Func<T> GetRateLimitStatus { get; set; }
47 public Predicate<T> RateLimitIf { get; private set; }
51 public bool ShouldSkipForRateLimiting()
53 // [JD]: Only pre-skip via predicate; percentage based adjusts rate after the call
54 if (RateLimitType != RateLimitType.ByPredicate)
59 if (RateLimitIf == null)
61 throw new InvalidOperationException("Rule is set to use predicate, but no predicate is defined.");
64 var status = default(T);
65 if (GetRateLimitStatus != null)
67 status = GetRateLimitStatus();
69 return !RateLimitIf(status);
72 public TimeSpan? CalculateNewInterval()
74 if (RateLimitType != RateLimitType.ByPercent)
79 if (!LimitToPercentOfTotal.HasValue)
83 var currentRateLimit = (IRateLimitStatus)GetRateLimitStatus();
84 if (currentRateLimit.RemainingUses == 0)
86 return currentRateLimit.NextReset - DateTime.Now;
88 var secondsUntilNextReset = (currentRateLimit.NextReset - DateTime.Now).TotalSeconds;
89 var desiredRetriesBeforeReset = currentRateLimit.RemainingUses * LimitToPercentOfTotal.Value;
90 var desiredInterval = (int)Math.Floor(secondsUntilNextReset / desiredRetriesBeforeReset);
91 return new TimeSpan(0, 0, 0, desiredInterval);