public virtual void UpdateLimit(string bucketId, RateLimitInfo info) { if (info.IsGlobal) { _globalWaitUntil = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value + (info.Lag?.TotalMilliseconds ?? 0.0)); } else { var bucket = _buckets.GetOrAdd(bucketId, x => new RequestBucket(this)); bucket.UpdateRateLimit(info); } }
public void UpdateRateLimit(RateLimitInfo info) { if (WindowCount == 0) { return; } lock (_lock) { bool hasQueuedReset = _resetsAt != null; if (info.Limit.HasValue && WindowCount != info.Limit.Value) { WindowCount = info.Limit.Value; _semaphore = info.Remaining.Value; } long now = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); DateTimeOffset?resetsAt = null; //Using X-RateLimit-Remaining causes a race condition /*if (info.Remaining.HasValue) * _semaphore = info.Remaining.Value;*/ if (info.RetryAfter.HasValue) //Millis { resetsAt = DateTimeOffset.UtcNow.AddMilliseconds(info.RetryAfter.Value); } else if (info.Reset.HasValue) //Secs { resetsAt = info.Reset.Value.AddSeconds(info.Lag?.TotalSeconds ?? 1.0); } if (resetsAt == null) { WindowCount = 0; //No rate limit info, disable limits on this bucket (should only ever happen with a user token) return; } if (!hasQueuedReset || resetsAt > _resetsAt) { _resetsAt = resetsAt; LastAttemptAt = resetsAt.Value; //Make sure we dont destroy this until after its been reset if (!hasQueuedReset) { int millis = (int)Math.Ceiling((_resetsAt.Value - DateTimeOffset.UtcNow).TotalMilliseconds); var _ = QueueReset(millis); } } } }