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
|