Skip to content

Commit

Permalink
Change the limiter.
Browse files Browse the repository at this point in the history
  • Loading branch information
hamidmayeli committed Oct 24, 2019
1 parent d14d832 commit 21877fe
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 49 deletions.
49 changes: 0 additions & 49 deletions Olive.EventBus/Limiter.cs

This file was deleted.

20 changes: 20 additions & 0 deletions Olive/-Extensions/Double.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,26 @@ public static bool AlmostEquals(this float @this, float otherValue, float tolera
/// <param name="maxValue">Determines the maximum value for comparing.</param>
public static int LimitWithin(this int @this, int minValue, int maxValue) => @this.LimitMin(minValue).LimitMax(maxValue);

/// <summary>
/// Determines the maximum limitation of two values.
/// </summary>
/// <param name="maxValue">If this value is smaller than {maxValue}, this value is returned, owherwise, {maxvalue} is returned.</param>
public static long LimitMax(this long @this, long maxValue) => @this > maxValue ? maxValue : @this;

/// <summary>
/// Determines the minimum limitation of two values.
/// </summary>
/// <param name="minValue">If this value is greater than {minValue}, this value is returned, owherwise, {minvalue} is returned.</param>
public static long LimitMin(this long @this, long minValue) => @this < minValue ? minValue : @this;

/// <summary>
/// Determines the minimum and maximum limitation of two values.
/// If this value is between {minValue} and {maxValue}, this value is returned. If this value is smaller than {minvalue}, {minvalue} is returned. If this value is greater than {maxvalue}, {maxvalue} is returned.
/// </summary>
/// <param name="minValue">Determines the minimum value for comparing.</param>
/// <param name="maxValue">Determines the maximum value for comparing.</param>
public static long LimitWithin(this long @this, long minValue, long maxValue) => @this.LimitMin(minValue).LimitMax(maxValue);

/// <summary>
/// Compare two values and returns 0, 1 or -1. If this value is equal to {othervalue}, it returns 0.
/// If this value is greater than {othervalue}, it returns 1. If this value is smaller than {othervalue}, it returns -1.
Expand Down
55 changes: 55 additions & 0 deletions Olive/Utilities/Limiter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using Olive;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Olive
{
/// <summary>
/// To limit the concurrent async process with a specific number.
/// </summary>
public class Limiter
{
readonly System.Timers.Timer Timer;
readonly ConcurrentDictionary<long, int> Cache = new ConcurrentDictionary<long, int>();

public int Limit { get; }

public Limiter(int limitTo)
{
Limit = limitTo;
Timer = new System.Timers.Timer(500.Milliseconds().TotalMilliseconds);
Timer.Elapsed += Timer_Elapsed;
Timer.Start();
}

public async Task Add(int count)
{
if (count > Limit) throw new ArgumentException("Provided argument is larger that the limition.");

var effectiveSince = LocalTime.UtcNow.AddSeconds(-1).Ticks;
var effective = Cache.Where(i => i.Key >= effectiveSince).ToArray();

var current = effective.Sum(i => i.Value);

if (current + count > Limit)
{
var oldest = effective.First().Key;
var delay = TimeSpan.FromTicks((oldest - effectiveSince).LimitMin(0) + 1);
await Task.Delay(delay);
await Add(count);
}

if (!Cache.TryAdd(LocalTime.UtcNow.Ticks, count))
await Add(count);
}

void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
var expiryPoint = LocalTime.UtcNow.AddSeconds(-1).Ticks;
Cache.RemoveWhereKey(key => key <= expiryPoint);
}
}
}

0 comments on commit 21877fe

Please sign in to comment.