Beispiel #1
0
        public async Task <Stream> SendAsync(IQueuedRequest request)
        {
            while (true)
            {
                try
                {
                    return(await SendAsyncInternal(request).ConfigureAwait(false));
                }
                catch (HttpRateLimitException ex)
                {
                    //When a 429 occurs, we drop all our locks.
                    //This is generally safe though since 429s actually occuring should be very rare.
                    RequestQueueBucket bucket;
                    bool success = FindBucket(ex.BucketId, out bucket);

                    await _queue.RaiseRateLimitTriggered(ex.BucketId, success?bucket.Definition : null, ex.RetryAfterMilliseconds).ConfigureAwait(false);

                    bucket.Pause(ex.RetryAfterMilliseconds);
                }
            }
        }
Beispiel #2
0
        private async Task <Stream> SendAsyncInternal(IQueuedRequest request)
        {
            var endTick = request.TimeoutTick;

            //Wait until a spot is open in our bucket
            if (_semaphore != null)
            {
                await EnterAsync(endTick).ConfigureAwait(false);
            }
            try
            {
                while (true)
                {
                    //Get our 429 state
                    Task notifier;
                    int  resumeTime;

                    lock (_pauseLock)
                    {
                        notifier   = _resumeNotifier.Task;
                        resumeTime = _pauseEndTick;
                    }

                    //Are we paused due to a 429?
                    if (!notifier.IsCompleted)
                    {
                        //If the 429 ends after the maximum time for this request, timeout immediately
                        if (endTick.HasValue && endTick.Value < resumeTime)
                        {
                            throw new TimeoutException();
                        }

                        //Wait for the 429 to complete
                        await notifier.ConfigureAwait(false);
                    }

                    try
                    {
                        //If there's a parent bucket, pass this request to them
                        if (Parent != null)
                        {
                            return(await Parent.SendAsyncInternal(request).ConfigureAwait(false));
                        }

                        //We have all our semaphores, send the request
                        return(await request.SendAsync().ConfigureAwait(false));
                    }
                    catch (HttpException ex) when(ex.StatusCode == HttpStatusCode.BadGateway)
                    {
                        continue;
                    }
                }
            }
            finally
            {
                //Make sure we put this entry back after WindowMilliseconds
                if (_semaphore != null)
                {
                    QueueExitAsync();
                }
            }
        }