shopify_unlimited 0.0.13.threadsafe → 0.0.14.threadsafe
Sign up to get free protection for your applications and to get access to all the features.
- 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
|