shopify_unlimited 0.0.13.threadsafe → 0.0.14.threadsafe
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/lib/shopify_unlimited/active_resource/base_extensions.rb +6 -3
- data/lib/shopify_unlimited/shopify_api/throttle.rb +75 -0
- data/lib/shopify_unlimited/version.rb +1 -1
- data/lib/shopify_unlimited.rb +1 -44
- metadata +3 -3
- data/lib/shopify_unlimited/active_resource/connection_extensions.rb +0 -49
    
        checksums.yaml
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            !binary "U0hBMQ==":
         | 
| 3 3 | 
             
              metadata.gz: !binary |-
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                MGJhYTI2MWQ4NjQxNjNlODZmN2I3ZTY3MjEzZGQ0MjIxZGZhZDI2ZQ==
         | 
| 5 5 | 
             
              data.tar.gz: !binary |-
         | 
| 6 | 
            -
                 | 
| 6 | 
            +
                ZTQzMDliNDE3MGZmY2RiY2E5OTRjYjdkZDRmZjYwNjZhNDQ2ZmE4Yw==
         | 
| 7 7 | 
             
            !binary "U0hBNTEy":
         | 
| 8 8 | 
             
              metadata.gz: !binary |-
         | 
| 9 | 
            -
                 | 
| 10 | 
            -
                 | 
| 11 | 
            -
                 | 
| 9 | 
            +
                NjgyNzMxMTE5NWIyOGQxODAyNWI4YTdkZGUwZjBiNTQwOWQzMWJhZDRiYjNk
         | 
| 10 | 
            +
                MzA3MDI3YTJiOGI4YjNiODRjN2FlNDAxMjI5NTRhNzE5ODVlYTU3NjhmNWRj
         | 
| 11 | 
            +
                MDRjN2RkNmFiNzc1YjRiMWJlN2UwY2QyZTQyMzdlM2U2OWZiNDI=
         | 
| 12 12 | 
             
              data.tar.gz: !binary |-
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 13 | 
            +
                ZWE3MjM3ODk3NmY3ZGYzNDZjYzI4ZjU4OGZhNGNmNzU1ZGFkNDk1ZDIwYWFj
         | 
| 14 | 
            +
                MjE5OGE2ZjBiNjM1YzFkMjk4NmJhMjQ4YTRhNjVlNWQ3YzU0NTg1MzQzMDY4
         | 
| 15 | 
            +
                ZWQxZDEwNzlkMDRjMjc0ZDhiMGMzMjdlYzZlZGM0MzhhNDM5MWU=
         | 
| @@ -38,15 +38,18 @@ module ActiveResource | |
| 38 38 | 
             
                      page = 0
         | 
| 39 39 | 
             
                      # as long as the number of results we got back is not less than the limit we (probably) have more to fetch
         | 
| 40 40 | 
             
                      while( (results.count - last_count) >= limit) do
         | 
| 41 | 
            -
                        raise ShopifyAPI::Limits::Error.new if ShopifyAPI.credit_maxed?
         | 
| 42 41 | 
             
                        page +=1
         | 
| 43 42 | 
             
                        last_count = results.count
         | 
| 44 43 | 
             
                        options[:params][:page] = page
         | 
| 45 | 
            -
                         | 
| 44 | 
            +
                        ShopifyAPI::Shop.current.throttle.run do
         | 
| 45 | 
            +
                          results.concat find_every.bind(self).call(options)
         | 
| 46 | 
            +
                        end
         | 
| 46 47 | 
             
                        results.requests_made += 1
         | 
| 47 48 | 
             
                      end
         | 
| 48 49 | 
             
                    else
         | 
| 49 | 
            -
                       | 
| 50 | 
            +
                      ShopifyAPI::Shop.current.throttle.run do
         | 
| 51 | 
            +
                        results.concat find_every.bind(self).call(options)
         | 
| 52 | 
            +
                      end
         | 
| 50 53 | 
             
                      results.requests_made += 1
         | 
| 51 54 | 
             
                    end
         | 
| 52 55 |  | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            # this allows multiple concurrent workers to behave well, almost
         | 
| 2 | 
            +
            # never triggering a 429, and distributing requests fairly evenly,
         | 
| 3 | 
            +
            # rather than 1 worker hogging the bulk
         | 
| 4 | 
            +
            # of requests until finished, which will typically happen with
         | 
| 5 | 
            +
            # any naive, non-stochastic implementation.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            module ShopifyAPI
         | 
| 9 | 
            +
              class Shop
         | 
| 10 | 
            +
                def throttle
         | 
| 11 | 
            +
                  @throttle ||= Throttle.new
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              class Throttle
         | 
| 16 | 
            +
                attr_accessor :throttle, :throttle_increment, :requests_threshold
         | 
| 17 | 
            +
                def initialize
         | 
| 18 | 
            +
                  @throttle = 0.6
         | 
| 19 | 
            +
                  @throttle_increment = @throttle
         | 
| 20 | 
            +
                  @requests_threshold = 10
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def run(&block)
         | 
| 24 | 
            +
                  value = nil
         | 
| 25 | 
            +
                  retries ||= 0
         | 
| 26 | 
            +
                  begin
         | 
| 27 | 
            +
                    left = ShopifyAPI.credit_left
         | 
| 28 | 
            +
                    over = @requests_threshold - left
         | 
| 29 | 
            +
                    if over > 0
         | 
| 30 | 
            +
                      @throttle += (over * rand/20) + rand/10
         | 
| 31 | 
            +
                      sleep @throttle + rand/10
         | 
| 32 | 
            +
                    else
         | 
| 33 | 
            +
                      @throttle = (0.94 + rand/20) * @throttle
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                    t = Time.now
         | 
| 36 | 
            +
                    value = yield
         | 
| 37 | 
            +
                  rescue ActiveResource::ClientError => e
         | 
| 38 | 
            +
                    case e.response.code
         | 
| 39 | 
            +
                    when '404'
         | 
| 40 | 
            +
                      logger.fatal "Shopify returned not found"
         | 
| 41 | 
            +
                      sleep 5 + retries + (rand * rand * 5)
         | 
| 42 | 
            +
                      retries += 1
         | 
| 43 | 
            +
                      if retries < 4
         | 
| 44 | 
            +
                        ActiveResource::Base.logger = Logger.new(STDOUT) 
         | 
| 45 | 
            +
                        retry
         | 
| 46 | 
            +
                      else
         | 
| 47 | 
            +
                        ActiveResource::Base.logger = nil
         | 
| 48 | 
            +
                        raise
         | 
| 49 | 
            +
                      end
         | 
| 50 | 
            +
                    when '429'
         | 
| 51 | 
            +
                      logger.warn "Shopify hit api limit"
         | 
| 52 | 
            +
                      @throttle += rand/5
         | 
| 53 | 
            +
                      retries += 1
         | 
| 54 | 
            +
                      sleep (@throttle * 4 * retries) + rand/10
         | 
| 55 | 
            +
                      if retries < 10
         | 
| 56 | 
            +
                        retry
         | 
| 57 | 
            +
                      else
         | 
| 58 | 
            +
                        raise
         | 
| 59 | 
            +
                      end
         | 
| 60 | 
            +
                    else
         | 
| 61 | 
            +
                      raise
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  requests_made = left - ShopifyAPI.credit_left
         | 
| 65 | 
            +
                  if requests_made > 1
         | 
| 66 | 
            +
                    @throttle += (rand/20) * requests_made
         | 
| 67 | 
            +
                    sleep [0, (t + (requests_made * @throttle) - Time.now)].max + rand/10
         | 
| 68 | 
            +
                  else
         | 
| 69 | 
            +
                    @throttle = (0.94 + rand/20) * @throttle
         | 
| 70 | 
            +
                    sleep rand/20
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                  value
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         | 
    
        data/lib/shopify_unlimited.rb
    CHANGED
    
    | @@ -1,46 +1,3 @@ | |
| 1 1 | 
             
            require "shopify_unlimited/version"
         | 
| 2 2 | 
             
            require 'shopify_unlimited/active_resource/base_extensions'
         | 
| 3 | 
            -
            require 'shopify_unlimited/ | 
| 4 | 
            -
             | 
| 5 | 
            -
            module ShopifyUnlimited
         | 
| 6 | 
            -
              SHOPIFY_CREDIT_LIMIT_PERIOD = 5.minutes
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              class << self
         | 
| 9 | 
            -
                attr_accessor :use_memcached
         | 
| 10 | 
            -
                def memcached
         | 
| 11 | 
            -
                  return nil unless use_memcached
         | 
| 12 | 
            -
                  @memcached ||= Dalli::Client.new()
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def cache_key
         | 
| 16 | 
            -
                  URI.parse(ShopifyAPI::Base.site.to_s).host + "_api_reset_time"
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                def cached_time(max)
         | 
| 20 | 
            -
                  now = Time.now
         | 
| 21 | 
            -
                  result = now
         | 
| 22 | 
            -
                  return result unless memcached
         | 
| 23 | 
            -
                  unless memcached.add(cache_key, now, 500)
         | 
| 24 | 
            -
                    memcached.cas(cache_key, 500) do |cached_time|
         | 
| 25 | 
            -
                      result = ((now - cached_time) > max) ? now : cached_time
         | 
| 26 | 
            -
                      result
         | 
| 27 | 
            -
                    end 
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                  result
         | 
| 30 | 
            -
                end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                def set_cached_time(time)
         | 
| 33 | 
            -
                  return unless memcached
         | 
| 34 | 
            -
                  memcached.set(cache_key, time, 500)
         | 
| 35 | 
            -
                end  
         | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
                def estimated_time_until_reset
         | 
| 39 | 
            -
                  credit_record = ShopifyAPI::Base.connection.shopify_credit
         | 
| 40 | 
            -
                  time = credit_record.time unless credit_record.nil?
         | 
| 41 | 
            -
                  time ||= cached_time(ShopifyUnlimited::SHOPIFY_CREDIT_LIMIT_PERIOD)
         | 
| 42 | 
            -
                  est = ShopifyUnlimited::SHOPIFY_CREDIT_LIMIT_PERIOD - (Time.now - time)
         | 
| 43 | 
            -
                  [est, 0].max
         | 
| 44 | 
            -
                end
         | 
| 45 | 
            -
              end
         | 
| 46 | 
            -
            end
         | 
| 3 | 
            +
            require 'shopify_unlimited/shopify_api/throttle'
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: shopify_unlimited
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.0. | 
| 4 | 
            +
              version: 0.0.14.threadsafe
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Michael Johnston
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2014-03- | 
| 11 | 
            +
            date: 2014-03-13 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activeresource
         | 
| @@ -109,7 +109,7 @@ files: | |
| 109 109 | 
             
            - Rakefile
         | 
| 110 110 | 
             
            - lib/shopify_unlimited.rb
         | 
| 111 111 | 
             
            - lib/shopify_unlimited/active_resource/base_extensions.rb
         | 
| 112 | 
            -
            - lib/shopify_unlimited/ | 
| 112 | 
            +
            - lib/shopify_unlimited/shopify_api/throttle.rb
         | 
| 113 113 | 
             
            - lib/shopify_unlimited/version.rb
         | 
| 114 114 | 
             
            - shopify_unlimited.gemspec
         | 
| 115 115 | 
             
            - spec/spec_helper.rb
         | 
| @@ -1,49 +0,0 @@ | |
| 1 | 
            -
            module ::ShopifyUnlimited
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              class CreditUsed    
         | 
| 4 | 
            -
             | 
| 5 | 
            -
                attr_accessor :time, :used
         | 
| 6 | 
            -
                def initialize(used)
         | 
| 7 | 
            -
                  @time = Time.now
         | 
| 8 | 
            -
                  @used = used
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def stale?(used)
         | 
| 12 | 
            -
                  (@used > used) || ((Time.now - @time) > ShopifyUnlimited::SHOPIFY_CREDIT_LIMIT_PERIOD)
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def estimated_time_until_reset
         | 
| 16 | 
            -
                  est = ShopifyUnlimited::SHOPIFY_CREDIT_LIMIT_PERIOD - (Time.now - @time)
         | 
| 17 | 
            -
                  [est, 0].max
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
            end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            module ::ActiveResource
         | 
| 24 | 
            -
              class Connection
         | 
| 25 | 
            -
                SHOPIFY_CREDIT_LIMIT_HEADER_PARAM = 'http_x_shopify_shop_api_call_limit'
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                attr_reader :shopify_credit
         | 
| 28 | 
            -
                def handle_response_with_response_time_capture(response)
         | 
| 29 | 
            -
                  handle_response_without_response_time_capture(response)
         | 
| 30 | 
            -
                  
         | 
| 31 | 
            -
                  if(shopify_credit_header = response[SHOPIFY_CREDIT_LIMIT_HEADER_PARAM])
         | 
| 32 | 
            -
                    used = shopify_credit_header.split('/').shift.to_i
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                    if @shopify_credit.nil?
         | 
| 35 | 
            -
                      cached_time = ::ShopifyUnlimited.cached_time(ShopifyUnlimited::SHOPIFY_CREDIT_LIMIT_PERIOD)
         | 
| 36 | 
            -
                      @shopify_credit = ::ShopifyUnlimited::CreditUsed.new(used)
         | 
| 37 | 
            -
                      @shopify_credit.time = cached_time
         | 
| 38 | 
            -
                    elsif @shopify_credit.stale?(used)
         | 
| 39 | 
            -
                      @shopify_credit = ::ShopifyUnlimited::CreditUsed.new(used)
         | 
| 40 | 
            -
                      ::ShopifyUnlimited.set_cached_time(Time.now)
         | 
| 41 | 
            -
                    else
         | 
| 42 | 
            -
                      @shopify_credit.used = used
         | 
| 43 | 
            -
                    end
         | 
| 44 | 
            -
                  end
         | 
| 45 | 
            -
                  response
         | 
| 46 | 
            -
                end
         | 
| 47 | 
            -
                alias_method_chain :handle_response, :response_time_capture
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
            end
         |