4me-sdk 1.1.4 → 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/LICENSE +1 -1
- data/README.md +3 -2
- data/lib/sdk4me/client.rb +29 -9
- data/lib/sdk4me/client/response.rb +4 -0
- data/lib/sdk4me/client/version.rb +1 -1
- data/spec/lib/sdk4me/client_spec.rb +35 -3
- data/spec/lib/sdk4me/response_spec.rb +4 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5709d9ce126fa6349fdff96ab4a2dd1c80b8653a
|
4
|
+
data.tar.gz: 56ea4d39c7dce6e5c0578f0eb5ab1bbeb154622d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 754794a8253b590ddfd4064d2d96e9bae96597ab89c0169c6ebdb7fc8db4dd9035e7a0770be6f6644cff362a9f0dc5e061cb3992e15e6502556921bbdd997c5a
|
7
|
+
data.tar.gz: 80eaad3b45968a8ca3e1ce3afa4a6750c74105ba188122e1bcaf800ea87c64ab63c88893d70ee32793bf8bc19b22a38f5cec830935c153a03ccb978c83fb1607
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
4me-sdk (1.1.
|
4
|
+
4me-sdk (1.1.5)
|
5
5
|
activesupport (>= 4.2)
|
6
6
|
gem_config (>= 0.3)
|
7
7
|
mime-types (>= 3.0)
|
@@ -9,21 +9,21 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activesupport (5.2.
|
12
|
+
activesupport (5.2.2)
|
13
13
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
14
|
i18n (>= 0.7, < 2)
|
15
15
|
minitest (~> 5.1)
|
16
16
|
tzinfo (~> 1.1)
|
17
17
|
addressable (2.5.2)
|
18
18
|
public_suffix (>= 2.0.2, < 4.0)
|
19
|
-
concurrent-ruby (1.1.
|
19
|
+
concurrent-ruby (1.1.4)
|
20
20
|
crack (0.4.3)
|
21
21
|
safe_yaml (~> 1.0.0)
|
22
22
|
diff-lcs (1.3)
|
23
23
|
docile (1.3.1)
|
24
24
|
gem_config (0.3.1)
|
25
25
|
hashdiff (0.3.7)
|
26
|
-
i18n (1.
|
26
|
+
i18n (1.5.1)
|
27
27
|
concurrent-ruby (~> 1.0)
|
28
28
|
json (2.1.0)
|
29
29
|
mime-types (3.2.2)
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -40,9 +40,10 @@ All options available:
|
|
40
40
|
* _max_retry_time_: maximum nr of seconds to wait for server to respond (default = 5400 = 1.5 hours)<br/>
|
41
41
|
The sleep time between retries starts at 2 seconds and doubles after each retry, i.e.
|
42
42
|
2, 6, 18, 54, 162, 486, 1458, 4374, 13122, ... seconds.<br/>
|
43
|
-
|
43
|
+
Set to 0 to prevent retries.
|
44
44
|
* _read_timeout_: [HTTP read timeout](http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-read_timeout-3D) in seconds (default = 25)
|
45
|
-
* _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](http://developer.4me.com/v1/#rate-limiting) is lifted, default: `false
|
45
|
+
* _block_at_rate_limit_: Set to `true` to block the request until the [rate limit](http://developer.4me.com/v1/#rate-limiting) is lifted, default: `false`<br/>
|
46
|
+
The `Retry-After` header is used to compute when the retry should be performed. If that moment is later than the _max_retry_time_ the request will not be blocked and the throttled response is returned.
|
46
47
|
* _proxy_host_: Define in case HTTP traffic needs to go through a proxy
|
47
48
|
* _proxy_port_: Port of the proxy, defaults to 8080
|
48
49
|
* _proxy_user_: Proxy user
|
data/lib/sdk4me/client.rb
CHANGED
@@ -298,14 +298,25 @@ module Sdk4me
|
|
298
298
|
end
|
299
299
|
|
300
300
|
module SendWithRateLimitBlock
|
301
|
-
# Wraps the _send method with retries when the server does not
|
301
|
+
# Wraps the _send method with retries when the server does not respond, see +initialize+ option +:rate_limit_block+
|
302
302
|
def _send(request, domain = @domain, port = @port, ssl = @ssl)
|
303
303
|
return super(request, domain, port, ssl) unless option(:block_at_rate_limit)
|
304
304
|
now = Time.now
|
305
|
+
timed_out = false
|
306
|
+
# respect the max_retry_time with fallback to max 1 hour and 1 minute wait time
|
307
|
+
max_retry_time = option(:max_retry_time) > 0 ? option(:max_retry_time) : 3660
|
305
308
|
begin
|
306
309
|
_response = super(request, domain, port, ssl)
|
307
|
-
|
308
|
-
|
310
|
+
if _response.throttled?
|
311
|
+
retry_after = _response.retry_after == 0 ? 300 : [_response.retry_after, 2].max
|
312
|
+
if (Time.now - now + retry_after) < max_retry_time
|
313
|
+
@logger.warn { "Request throttled, trying again in #{retry_after} seconds: #{_response.message}" }
|
314
|
+
sleep(retry_after)
|
315
|
+
else
|
316
|
+
timed_out = true
|
317
|
+
end
|
318
|
+
end
|
319
|
+
end while _response.throttled? && !timed_out
|
309
320
|
_response
|
310
321
|
end
|
311
322
|
end
|
@@ -314,15 +325,24 @@ module Sdk4me
|
|
314
325
|
module SendWithRetries
|
315
326
|
# Wraps the _send method with retries when the server does not respond, see +initialize+ option +:retries+
|
316
327
|
def _send(request, domain = @domain, port = @port, ssl = @ssl)
|
328
|
+
return super(request, domain, port, ssl) unless option(:max_retry_time) > 0
|
317
329
|
retries = 0
|
318
|
-
sleep_time =
|
319
|
-
|
330
|
+
sleep_time = 1
|
331
|
+
now = Time.now
|
332
|
+
timed_out = false
|
320
333
|
begin
|
321
334
|
_response = super(request, domain, port, ssl)
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
335
|
+
# throttling is handled separately
|
336
|
+
if !_response.success? && !_response.throttled?
|
337
|
+
sleep_time *= 2
|
338
|
+
if (Time.now - now + sleep_time) < option(:max_retry_time)
|
339
|
+
@logger.warn { "Request failed, retry ##{retries += 1} in #{sleep_time} seconds: #{_response.message}" }
|
340
|
+
sleep(sleep_time)
|
341
|
+
else
|
342
|
+
timed_out = true
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end while !_response.success? && !_response.throttled? && !timed_out
|
326
346
|
_response
|
327
347
|
end
|
328
348
|
end
|
@@ -111,6 +111,10 @@ module Sdk4me
|
|
111
111
|
!!(@response.code.to_s == '429' || (message && message =~ /Too Many Requests/))
|
112
112
|
end
|
113
113
|
|
114
|
+
def retry_after
|
115
|
+
@current_page ||= @response.header['Retry-After'].to_i
|
116
|
+
end
|
117
|
+
|
114
118
|
def to_s
|
115
119
|
valid? ? json.to_s : message
|
116
120
|
end
|
@@ -282,7 +282,8 @@ describe Sdk4me::Client do
|
|
282
282
|
context 'import' do
|
283
283
|
before(:each) do
|
284
284
|
@client = Sdk4me::Client.new(api_token: 'secret', max_retry_time: -1)
|
285
|
-
|
285
|
+
csv_mime_type = ['text/csv', 'text/comma-separated-values'].detect{|t| MIME::Types[t].any?} # which mime type is used depends on version of mime-types gem
|
286
|
+
@multi_part_body = "--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"type\"\r\n\r\npeople\r\n--0123456789ABLEWASIEREISAWELBA9876543210\r\nContent-Disposition: form-data; name=\"file\"; filename=\"#{@fixture_dir}/people.csv\"\r\nContent-Type: #{csv_mime_type}\r\n\r\nPrimary Email,Name\nchess.cole@example.com,Chess Cole\ned.turner@example.com,Ed Turner\r\n--0123456789ABLEWASIEREISAWELBA9876543210--"
|
286
287
|
@multi_part_headers = {'Accept'=>'*/*', 'Content-Type'=>'multipart/form-data; boundary=0123456789ABLEWASIEREISAWELBA9876543210', 'User-Agent'=>'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/523.10.6 (KHTML, like Gecko) Version/3.0.4 Safari/523.10.6'}
|
287
288
|
|
288
289
|
@import_queued_response = {body: {state: 'queued'}.to_json}
|
@@ -477,10 +478,11 @@ describe Sdk4me::Client do
|
|
477
478
|
|
478
479
|
it 'should not retry 4 times when max_retry_time = 16' do
|
479
480
|
stub = stub_request(:get, 'https://api.4me.com/v1/me').with(basic_auth: ['secret', 'x']).to_raise(StandardError.new('network error'))
|
480
|
-
[2,4,8
|
481
|
+
[2,4,8].each_with_index do |secs, i|
|
481
482
|
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
482
483
|
expect_log("Request failed, retry ##{i+1} in #{secs} seconds: 500: No Response from Server - network error for 'api.4me.com:443/v1/me'", :warn)
|
483
484
|
end
|
485
|
+
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
484
486
|
|
485
487
|
client = Sdk4me::Client.new(api_token: 'secret', max_retry_time: 16)
|
486
488
|
allow(client).to receive(:sleep)
|
@@ -522,7 +524,37 @@ describe Sdk4me::Client do
|
|
522
524
|
it 'should block on rate limit when block_at_rate_limit is true' do
|
523
525
|
stub = stub_request(:get, 'https://api.4me.com/v1/me').with(basic_auth: ['secret', 'x']).to_return(status: 429, body: {message: 'Too Many Requests'}.to_json).then.to_return(body: {name: 'my name'}.to_json)
|
524
526
|
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
525
|
-
expect_log('Request throttled, trying again in
|
527
|
+
expect_log('Request throttled, trying again in 300 seconds: 429: Too Many Requests', :warn)
|
528
|
+
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
529
|
+
expect_log(%(Response:\n{\n "name": "my name"\n}), :debug )
|
530
|
+
|
531
|
+
client = Sdk4me::Client.new(api_token: 'secret', block_at_rate_limit: true)
|
532
|
+
allow(client).to receive(:sleep)
|
533
|
+
response = client.get('me')
|
534
|
+
expect(stub).to have_been_requested.times(2)
|
535
|
+
expect(response.valid?).to be_truthy
|
536
|
+
expect(response[:name]).to eq('my name')
|
537
|
+
end
|
538
|
+
|
539
|
+
it 'should block on rate limit using Retry-After when block_at_rate_limit is true' do
|
540
|
+
stub = stub_request(:get, 'https://api.4me.com/v1/me').with(basic_auth: ['secret', 'x']).to_return(status: 429, body: {message: 'Too Many Requests'}.to_json, headers: {'Retry-After' => '20'}).then.to_return(body: {name: 'my name'}.to_json)
|
541
|
+
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
542
|
+
expect_log('Request throttled, trying again in 20 seconds: 429: Too Many Requests', :warn)
|
543
|
+
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
544
|
+
expect_log(%(Response:\n{\n "name": "my name"\n}), :debug )
|
545
|
+
|
546
|
+
client = Sdk4me::Client.new(api_token: 'secret', block_at_rate_limit: true)
|
547
|
+
allow(client).to receive(:sleep)
|
548
|
+
response = client.get('me')
|
549
|
+
expect(stub).to have_been_requested.times(2)
|
550
|
+
expect(response.valid?).to be_truthy
|
551
|
+
expect(response[:name]).to eq('my name')
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'should block on rate limit using Retry-After with minimum of 2 seconds when block_at_rate_limit is true' do
|
555
|
+
stub = stub_request(:get, 'https://api.4me.com/v1/me').with(basic_auth: ['secret', 'x']).to_return(status: 429, body: {message: 'Too Many Requests'}.to_json, headers: {'Retry-After' => '1'}).then.to_return(body: {name: 'my name'}.to_json)
|
556
|
+
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
557
|
+
expect_log('Request throttled, trying again in 2 seconds: 429: Too Many Requests', :warn)
|
526
558
|
expect_log('Sending GET request to api.4me.com:443/v1/me', :debug )
|
527
559
|
expect_log(%(Response:\n{\n "name": "my name"\n}), :debug )
|
528
560
|
|
@@ -93,10 +93,10 @@ describe Sdk4me::Response do
|
|
93
93
|
stub_request(:get, 'https://api.4me.com/v1/organizations').with(basic_auth: ['secret', 'x']).to_return(body: '==$$!invalid')
|
94
94
|
response = @client.get('organizations')
|
95
95
|
|
96
|
-
message = "
|
97
|
-
expect(response.json[:message]).to
|
98
|
-
expect(response.json['message']).to
|
99
|
-
expect(response.message).to
|
96
|
+
message = "unexpected token at '==$$!invalid' for:\n#{response.body}"
|
97
|
+
expect(response.json[:message]).to include(message)
|
98
|
+
expect(response.json['message']).to include(message)
|
99
|
+
expect(response.message).to include(message)
|
100
100
|
end
|
101
101
|
|
102
102
|
it 'should have a blank message when single record is succesfully retrieved' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: 4me-sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 4me
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gem_config
|
@@ -171,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
171
|
version: '0'
|
172
172
|
requirements: []
|
173
173
|
rubyforge_project:
|
174
|
-
rubygems_version: 2.6
|
174
|
+
rubygems_version: 2.4.6
|
175
175
|
signing_key:
|
176
176
|
specification_version: 4
|
177
177
|
summary: The official 4me SDK for Ruby. Provides easy access to the APIs found at
|