Example #1
0
        public async Task <RequestResult <T> > Run <T>(CloneableRequestMessage baseRequest, ExecuteRequestAsync <T> executeRequestAsync)
        {
            var         accessToken = GetAccessToken(baseRequest);
            LeakyBucket bucket      = null;

            if (accessToken != null)
            {
                bucket = _shopAccessTokenToLeakyBucket.GetOrAdd(accessToken, _ => new LeakyBucket());
            }

            while (true)
            {
                var request = baseRequest.Clone();

                if (accessToken != null)
                {
                    await bucket.GrantAsync();
                }

                try
                {
                    var fullResult = await executeRequestAsync(request);

                    var bucketState = LeakyBucketState.Get(fullResult.Response);

                    if (bucketState != null)
                    {
                        bucket?.SetState(bucketState);
                    }

                    return(fullResult);
                }
                catch (ShopifyRateLimitException ex) when(ex.Reason == ShopifyRateLimitReason.BucketFull || !_retryOnlyIfLeakyBucketFull)
                {
                    //Only retry if breach caused by full bucket
                    //Other limits will bubble the exception because it's not clear how long the program should wait
                    //Even if there is a Retry-After header, we probably don't want the thread to sleep for potentially many hours
                    //
                    //An exception may still occur:
                    //-Shopify may have a slightly different algorithm
                    //-Shopify may change to a different algorithm in the future
                    //-There may be timing and latency delays
                    //-Multiple programs may use the same access token
                    //-Multiple instances of the same program may use the same access token
                    await Task.Delay(THROTTLE_DELAY);
                }
            }
        }
        public async Task <T> Run <T>(IFlurlClient baseRequest, JsonContent bodyContent, ExecuteRequestAsync <T> executeRequestAsync)
        {
            var         accessToken = GetAccessToken(baseRequest);
            LeakyBucket bucket      = null;

            if (accessToken != null)
            {
                bucket = _shopAccessTokenToLeakyBucket.GetOrAdd(accessToken, _ => new LeakyBucket());
            }

            while (true)
            {
                var request = baseRequest.Clone();
                var content = bodyContent?.Clone();

                if (accessToken != null)
                {
                    await bucket.GrantAsync();
                }

                try
                {
                    var fullResult = await executeRequestAsync(request, content);

                    var bucketState = this.GetBucketState(fullResult.Response);

                    if (bucketState != null)
                    {
                        bucket?.SetState(bucketState);
                    }

                    return(fullResult.Result);
                }
                catch (ShopifyRateLimitException)
                {
                    //An exception may still occur:
                    //-Shopify may have a slightly different algorithm
                    //-Shopify may change to a different algorithm in the future
                    //-There may be timing and latency delays
                    //-Multiple programs may use the same access token
                    //-Multiple instances of the same program may use the same access token
                    await Task.Delay(THROTTLE_DELAY);
                }
            }
        }
        public async Task <T> Run <T>(IRestClient client, IRestRequest request, ExecuteRequestAsync <T> executeRequestAsync)
        {
            string      accessToken = this.GetAccessToken(client);
            LeakyBucket bucket      = null;

            if (accessToken != null)
            {
                bucket = _shopAccessTokenToLeakyBucket.GetOrAdd(accessToken, _ => new LeakyBucket());
            }

Start:
            if (accessToken != null)
            {
                await bucket.GrantAsync();
            }
            try
            {
                var requestResult = await executeRequestAsync();

                int?bucketContentSize = this.GetBucketContentSize(requestResult.Response);

                if (bucketContentSize != null)
                {
                    bucket?.SetContentSize(bucketContentSize.Value);
                }

                return(requestResult.Result);
            }
            catch (ShopifyRateLimitException)
            {
                //An exception may still occur:
                //-Shopify may have a slightly different algorithm
                //-Shopify may change to a different algorithm in the future
                //-There may be timing and latency delays
                //-Multiple programs may use the same access token
                //-Multiple instance of the same program may use the same access token
                await Task.Delay(THROTTLE_DELAY);

                goto Start;
            }
        }
Example #4
0
 public MultiShopifyAPIBucket(Func <RequestContext> getRequestContext)
 {
     RESTBucket    = new LeakyBucket(DEFAULT_REST_MAX_AVAILABLE, DEFAULT_REST_RESTORE_RATE, getRequestContext);
     GraphQLBucket = new LeakyBucket(DEFAULT_GRAPHQL_MAX_AVAILABLE, DEFAULT_GRAPHQL_RESTORE_RATE, getRequestContext);
 }