1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-07 16:06:15 +00:00

Fix for ratelimiting possibly creating negative waits

This commit is contained in:
JKorf 2024-06-25 16:14:09 +02:00
parent ff0550b0fb
commit be68115099
6 changed files with 29 additions and 4 deletions

View File

@ -80,7 +80,10 @@ namespace CryptoExchange.Net.RateLimiting.Trackers
private TimeSpan DetermineWaitTime(int requestWeight) private TimeSpan DetermineWaitTime(int requestWeight)
{ {
var weightToRemove = Math.Max(Current - (Limit - requestWeight), 0); var weightToRemove = Math.Max(Current - (Limit - requestWeight), 0);
return TimeSpan.FromMilliseconds(Math.Ceiling(weightToRemove / DecreaseRate) * TimePeriod.TotalMilliseconds); var result = TimeSpan.FromMilliseconds(Math.Ceiling(weightToRemove / DecreaseRate) * TimePeriod.TotalMilliseconds);
if (result < TimeSpan.Zero)
return TimeSpan.Zero;
return result;
} }
} }
} }

View File

@ -97,7 +97,10 @@ namespace CryptoExchange.Net.RateLimiting.Trackers
private TimeSpan DetermineWaitTime() private TimeSpan DetermineWaitTime()
{ {
var checkTime = DateTime.UtcNow; var checkTime = DateTime.UtcNow;
return (_nextReset!.Value - checkTime) + _fixedWindowBuffer; var result = (_nextReset!.Value - checkTime) + _fixedWindowBuffer;
if (result < TimeSpan.Zero)
return TimeSpan.Zero;
return result;
} }
} }
} }

View File

@ -93,7 +93,10 @@ namespace CryptoExchange.Net.RateLimiting.Trackers
var checkTime = DateTime.UtcNow; var checkTime = DateTime.UtcNow;
var startCurrentWindow = checkTime.AddTicks(-(checkTime.Ticks % TimePeriod.Ticks)); var startCurrentWindow = checkTime.AddTicks(-(checkTime.Ticks % TimePeriod.Ticks));
var wait = startCurrentWindow.Add(TimePeriod) - checkTime; var wait = startCurrentWindow.Add(TimePeriod) - checkTime;
return wait.Add(_fixedWindowBuffer); var result = wait.Add(_fixedWindowBuffer);
if (result < TimeSpan.Zero)
return TimeSpan.Zero;
return result;
} }
} }
} }

View File

@ -16,6 +16,11 @@ namespace CryptoExchange.Net.RateLimiting.Trackers
private readonly List<LimitEntry> _entries; private readonly List<LimitEntry> _entries;
private int _currentWeight = 0; private int _currentWeight = 0;
/// <summary>
/// Additional wait time to apply to account for fluctuating request times
/// </summary>
private static readonly TimeSpan _slidingWindowBuffer = TimeSpan.FromMilliseconds(1000);
public SlidingWindowTracker(int limit, TimeSpan period) public SlidingWindowTracker(int limit, TimeSpan period)
{ {
Limit = limit; Limit = limit;
@ -89,7 +94,10 @@ namespace CryptoExchange.Net.RateLimiting.Trackers
removedWeight += entry.Weight; removedWeight += entry.Weight;
if (removedWeight >= weightToRemove) if (removedWeight >= weightToRemove)
{ {
return entry.Timestamp + TimePeriod - DateTime.UtcNow; var result = entry.Timestamp + TimePeriod + _slidingWindowBuffer - DateTime.UtcNow;
if (result < TimeSpan.Zero)
return TimeSpan.Zero;
return result;
} }
} }

View File

@ -80,6 +80,10 @@ namespace CryptoExchange.Net.Testing.Comparers
else if (jObj.Type == JTokenType.Array) else if (jObj.Type == JTokenType.Array)
{ {
var resultObj = enumerator.Current; var resultObj = enumerator.Current;
if (resultObj is string)
// string list
continue;
var resultProps = resultObj.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault())); var resultProps = resultObj.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault()));
var arrayConverterProperty = resultObj.GetType().GetCustomAttributes(typeof(JsonConverterAttribute), true).FirstOrDefault(); var arrayConverterProperty = resultObj.GetType().GetCustomAttributes(typeof(JsonConverterAttribute), true).FirstOrDefault();
var jsonConverter = ((JsonConverterAttribute)arrayConverterProperty!).ConverterType; var jsonConverter = ((JsonConverterAttribute)arrayConverterProperty!).ConverterType;

View File

@ -82,6 +82,10 @@ namespace CryptoExchange.Net.Testing.Comparers
else if (jObj.Type == JTokenType.Array) else if (jObj.Type == JTokenType.Array)
{ {
var resultObj = enumerator.Current; var resultObj = enumerator.Current;
if (resultObj is string)
// string list
continue;
var resultProps = resultObj.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault())); var resultProps = resultObj.GetType().GetProperties().Select(p => (p, p.GetCustomAttributes(typeof(ArrayPropertyAttribute), true).Cast<ArrayPropertyAttribute>().SingleOrDefault()));
var arrayConverterProperty = resultObj.GetType().GetCustomAttributes(typeof(JsonConverterAttribute), true).FirstOrDefault(); var arrayConverterProperty = resultObj.GetType().GetCustomAttributes(typeof(JsonConverterAttribute), true).FirstOrDefault();
var jsonConverter = ((JsonConverterAttribute)arrayConverterProperty!).ConverterType; var jsonConverter = ((JsonConverterAttribute)arrayConverterProperty!).ConverterType;