protected override async Task <HttpResponseMessage> ImplementationAsync( Func <Context, CancellationToken, Task <HttpResponseMessage> > action, Context context, CancellationToken ct, bool continueOnCapturedContext) { if (!context.TryGetValue(EndpointContextKey, out var endpointObj) || !(endpointObj is string endpoint)) { throw new ArgumentException("Must provide endpoint in Polly context"); } if (!context.TryGetValue(MajorContextKey, out var majorObj) || !(majorObj is ulong major)) { throw new ArgumentException("Must provide major in Polly context"); } // Check rate limit, throw if we're not allowed... _ratelimiter.AllowRequestOrThrow(endpoint, major, DateTimeOffset.Now); // We're OK, push it through var response = await action(context, ct).ConfigureAwait(continueOnCapturedContext); // Update rate limit state with headers var headers = RatelimitHeaders.Parse(response); _ratelimiter.HandleResponse(headers, endpoint, major); return(response); }
public void HandleResponse(RatelimitHeaders headers, string endpoint, ulong major) { if (!headers.HasRatelimitInfo) { return; } // TODO: properly calculate server time? if (headers.Global) { _logger.Warning( "Global rate limit hit, resetting at {GlobalRateLimitExpiry} (in {GlobalRateLimitResetAfter}!", _globalRateLimitExpiry, headers.ResetAfter); _globalRateLimitExpiry = headers.Reset; } else { // Update buckets first, then get it again, to properly "transfer" this info over to the new value _buckets.UpdateEndpointInfo(endpoint, headers.Bucket !, headers.Limit); var bucket = _buckets.GetBucket(endpoint, major); bucket?.HandleResponse(headers); } }