Skip to content

Commit

Permalink
Added rate limit update event
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf committed Nov 13, 2024
1 parent d21792d commit 4879703
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CryptoExchange.Net/RateLimiting/Guards/RateLimitGuard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public LimitCheck Check(RateLimitItemType type, RequestDefinition definition, st

var delay = tracker.GetWaitTime(requestWeight);
if (delay == default)
return LimitCheck.NotNeeded;
return LimitCheck.NotNeeded(Limit, TimeSpan, tracker.Current);

return LimitCheck.Needed(delay, Limit, TimeSpan, tracker.Current);
}
Expand Down
2 changes: 1 addition & 1 deletion CryptoExchange.Net/RateLimiting/Guards/SingleLimitGuard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public LimitCheck Check(RateLimitItemType type, RequestDefinition definition, st

var delay = tracker.GetWaitTime(requestWeight);
if (delay == default)
return LimitCheck.NotNeeded;
return LimitCheck.NotNeeded(_limit, _period, tracker.Current);

return LimitCheck.Needed(delay, _limit, _period, tracker.Current);
}
Expand Down
5 changes: 5 additions & 0 deletions CryptoExchange.Net/RateLimiting/Interfaces/IRateLimitGate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ public interface IRateLimitGate
/// </summary>
event Action<RateLimitEvent> RateLimitTriggered;

/// <summary>
/// Event when the rate limit is updated. Note that it's only updated when a request is send, so there are no specific updates when the current usage is decaying.
/// </summary>
event Action<RateLimitUpdateEvent>? RateLimitUpdated;

/// <summary>
/// Add a rate limit guard
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion CryptoExchange.Net/RateLimiting/LimitCheck.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ private LimitCheck(bool applicable, TimeSpan delay, int limit, TimeSpan period,
/// <summary>
/// No wait needed
/// </summary>
public static LimitCheck NotNeeded { get; } = new LimitCheck(true, default, default, default, default);
public static LimitCheck NotNeeded(int limit, TimeSpan period, int current) => new(true, default, limit, period, current);

/// <summary>
/// Wait needed
Expand Down
19 changes: 7 additions & 12 deletions CryptoExchange.Net/RateLimiting/RateLimitEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
namespace CryptoExchange.Net.RateLimiting
{
/// <summary>
/// Rate limit event
/// Rate limit triggered event
/// </summary>
public record RateLimitEvent
{
/// <summary>
/// Id of the item the limit was checked for
/// </summary>
public int ItemId { get; set; }
/// <summary>
/// Name of the API limit that is reached
/// </summary>
Expand Down Expand Up @@ -52,18 +56,9 @@ public record RateLimitEvent
/// <summary>
/// ctor
/// </summary>
/// <param name="apiLimit"></param>
/// <param name="limitDescription"></param>
/// <param name="definition"></param>
/// <param name="host"></param>
/// <param name="current"></param>
/// <param name="requestWeight"></param>
/// <param name="limit"></param>
/// <param name="timePeriod"></param>
/// <param name="delayTime"></param>
/// <param name="behaviour"></param>
public RateLimitEvent(string apiLimit, string limitDescription, RequestDefinition definition, string host, int current, int requestWeight, int? limit, TimeSpan? timePeriod, TimeSpan? delayTime, RateLimitingBehaviour behaviour)
public RateLimitEvent(int itemId, string apiLimit, string limitDescription, RequestDefinition definition, string host, int current, int requestWeight, int? limit, TimeSpan? timePeriod, TimeSpan? delayTime, RateLimitingBehaviour behaviour)
{
ItemId = itemId;
ApiLimit = apiLimit;
LimitDescription = limitDescription;
RequestDefinition = definition;
Expand Down
8 changes: 6 additions & 2 deletions CryptoExchange.Net/RateLimiting/RateLimitGate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public class RateLimitGate : IRateLimitGate

/// <inheritdoc />
public event Action<RateLimitEvent>? RateLimitTriggered;
/// <inheritdoc />
public event Action<RateLimitUpdateEvent>? RateLimitUpdated;

/// <summary>
/// ctor
Expand Down Expand Up @@ -105,7 +107,7 @@ private async Task<CallResult> CheckGuardsAsync(IEnumerable<IRateLimitGuard> gua
else
logger.RateLimitRequestFailed(itemId, definition.Path, guard.Name, guard.Description);

RateLimitTriggered?.Invoke(new RateLimitEvent(_name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour));
RateLimitTriggered?.Invoke(new RateLimitEvent(itemId, _name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour));
return new CallResult(new ClientRateLimitError($"Rate limit check failed on guard {guard.Name}; {guard.Description}"));
}

Expand All @@ -120,7 +122,7 @@ private async Task<CallResult> CheckGuardsAsync(IEnumerable<IRateLimitGuard> gua
else
logger.RateLimitDelayingRequest(itemId, definition.Path, result.Delay, guard.Name, description);

RateLimitTriggered?.Invoke(new RateLimitEvent(_name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour));
RateLimitTriggered?.Invoke(new RateLimitEvent(itemId, _name, guard.Description, definition, host, result.Current, requestWeight, result.Limit, result.Period, result.Delay, rateLimitingBehaviour));
await Task.Delay((int)result.Delay.TotalMilliseconds + 1, ct).ConfigureAwait(false);
await _semaphore.WaitAsync(ct).ConfigureAwait(false);
return await CheckGuardsAsync(guards, logger, itemId, type, definition, host, apiKey, requestWeight, rateLimitingBehaviour, ct).ConfigureAwait(false);
Expand All @@ -133,6 +135,8 @@ private async Task<CallResult> CheckGuardsAsync(IEnumerable<IRateLimitGuard> gua
var result = guard.ApplyWeight(type, definition, host, apiKey, requestWeight);
if (result.IsApplied)
{
RateLimitUpdated?.Invoke(new RateLimitUpdateEvent(itemId, _name, guard.Description, result.Current, result.Limit, result.Period));

if (type == RateLimitItemType.Connection)
logger.RateLimitAppliedConnection(itemId, guard.Name, guard.Description, result.Current);
else
Expand Down
50 changes: 50 additions & 0 deletions CryptoExchange.Net/RateLimiting/RateLimitUpdateEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using CryptoExchange.Net.Objects;
using System;

namespace CryptoExchange.Net.RateLimiting
{
/// <summary>
/// Rate limit update event
/// </summary>
public record RateLimitUpdateEvent
{
/// <summary>
/// Id of the item the limit was checked for
/// </summary>
public int ItemId { get; set; }
/// <summary>
/// Name of the API limit that is reached
/// </summary>
public string ApiLimit { get; set; } = string.Empty;
/// <summary>
/// Description of the limit that is reached
/// </summary>
public string LimitDescription { get; set; } = string.Empty;
/// <summary>
/// The current counter value
/// </summary>
public int Current { get; set; }
/// <summary>
/// The limit per time period
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// The time period the limit is for
/// </summary>
public TimeSpan? TimePeriod { get; set; }

/// <summary>
/// ctor
/// </summary>
public RateLimitUpdateEvent(int itemId, string apiLimit, string limitDescription, int current, int? limit, TimeSpan? timePeriod)
{
ItemId = itemId;
ApiLimit = apiLimit;
LimitDescription = limitDescription;
Current = current;
Limit = limit;
TimePeriod = timePeriod;
}

}
}

0 comments on commit 4879703

Please sign in to comment.