rack-idempotent 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/rack-idempotent/version.rb +1 -1
- data/lib/rack-idempotent.rb +19 -4
- data/spec/rack-idempotent_spec.rb +27 -1
- metadata +39 -20
data/lib/rack-idempotent.rb
CHANGED
@@ -3,7 +3,8 @@ require "rack-idempotent/version"
|
|
3
3
|
module Rack
|
4
4
|
class Idempotent
|
5
5
|
RETRY_LIMIT = 5
|
6
|
-
|
6
|
+
RETRY_HTTP_CODES = [502, 503, 504]
|
7
|
+
IDEMPOTENT_HTTP_CODES = [*RETRY_HTTP_CODES, 408]
|
7
8
|
IDEMPOTENT_ERROR_CLASSES = [Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH]
|
8
9
|
|
9
10
|
class RetryLimitExceeded < Exception
|
@@ -24,6 +25,9 @@ module Rack
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
28
|
+
class Retryable < StandardError
|
29
|
+
end
|
30
|
+
|
27
31
|
def initialize(app)
|
28
32
|
@app= app
|
29
33
|
end
|
@@ -38,15 +42,26 @@ module Rack
|
|
38
42
|
raise HTTPException.new(status, headers, body) if IDEMPOTENT_HTTP_CODES.include?(status)
|
39
43
|
env.merge!(dup_env)
|
40
44
|
[status, headers, body]
|
41
|
-
rescue *IDEMPOTENT_ERROR_CLASSES, HTTPException => ie
|
45
|
+
rescue *IDEMPOTENT_ERROR_CLASSES, HTTPException, Retryable => ie
|
42
46
|
idempotent_exceptions << ie
|
43
47
|
if env['client.retries'] > RETRY_LIMIT - 1
|
44
48
|
raise(RetryLimitExceeded.new(idempotent_exceptions))
|
45
49
|
else
|
46
|
-
env[
|
47
|
-
|
50
|
+
if retry?(status, env["REQUEST_METHOD"])
|
51
|
+
env['client.retries'] += 1
|
52
|
+
retry
|
53
|
+
else
|
54
|
+
raise
|
55
|
+
end
|
48
56
|
end
|
49
57
|
end
|
50
58
|
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def retry?(response_status, request_method)
|
63
|
+
RETRY_HTTP_CODES.include?(response_status) || request_method == "GET"
|
64
|
+
end
|
65
|
+
|
51
66
|
end
|
52
67
|
end
|
@@ -37,6 +37,14 @@ describe Rack::Idempotent do
|
|
37
37
|
env['client.retries'].should == 2
|
38
38
|
end
|
39
39
|
|
40
|
+
it "should retry Rack::Idempotent::Retryable" do
|
41
|
+
RaiseUp.errors = [Rack::Idempotent::Retryable, Rack::Idempotent::Retryable]
|
42
|
+
client.get("/alsodoesntmatter")
|
43
|
+
|
44
|
+
env = CaptureEnv.env
|
45
|
+
env['client.retries'].should == 2
|
46
|
+
end
|
47
|
+
|
40
48
|
it "should raise Rack::Idempotent::RetryLimitExceeded when retry limit is reached" do
|
41
49
|
RaiseUp.errors = (Rack::Idempotent::RETRY_LIMIT + 1).times.map{|i| Errno::ETIMEDOUT}
|
42
50
|
|
@@ -47,7 +55,7 @@ describe Rack::Idempotent do
|
|
47
55
|
end
|
48
56
|
|
49
57
|
[502, 503, 504, 408].each do |code|
|
50
|
-
it "retries #{code}" do
|
58
|
+
it "retries GET #{code}" do
|
51
59
|
RaiseUp.errors = [code]
|
52
60
|
client.get("/something")
|
53
61
|
env = CaptureEnv.env
|
@@ -55,6 +63,24 @@ describe Rack::Idempotent do
|
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
66
|
+
[502, 503, 504].each do |code|
|
67
|
+
it "retries POST #{code}" do
|
68
|
+
RaiseUp.errors = [code]
|
69
|
+
client.post("/something")
|
70
|
+
env = CaptureEnv.env
|
71
|
+
env['client.retries'].should == 1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
it "doesn't retry POST when return code is 408" do
|
76
|
+
RaiseUp.errors = [408]
|
77
|
+
lambda do
|
78
|
+
client.post("/something")
|
79
|
+
end.should raise_error(Rack::Idempotent::HTTPException)
|
80
|
+
env = CaptureEnv.env
|
81
|
+
env['client.retries'].should == 0
|
82
|
+
end
|
83
|
+
|
58
84
|
it "should store exceptions raised" do
|
59
85
|
RaiseUp.errors = [502, Errno::ECONNREFUSED, 408, 504, Errno::EHOSTUNREACH, Errno::ETIMEDOUT]
|
60
86
|
errors = RaiseUp.errors.dup
|
metadata
CHANGED
@@ -1,23 +1,33 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-idempotent
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Ines Sombra
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
17
|
+
|
18
|
+
date: 2012-02-07 00:00:00 Z
|
13
19
|
dependencies: []
|
20
|
+
|
14
21
|
description: Retry logic for rack-client
|
15
|
-
email:
|
22
|
+
email:
|
16
23
|
- isombra@engineyard.com
|
17
24
|
executables: []
|
25
|
+
|
18
26
|
extensions: []
|
27
|
+
|
19
28
|
extra_rdoc_files: []
|
20
|
-
|
29
|
+
|
30
|
+
files:
|
21
31
|
- .gitignore
|
22
32
|
- .travis.yml
|
23
33
|
- Gemfile
|
@@ -29,30 +39,39 @@ files:
|
|
29
39
|
- rack-idempotent.gemspec
|
30
40
|
- spec/rack-idempotent_spec.rb
|
31
41
|
- spec/spec_helper.rb
|
32
|
-
homepage:
|
42
|
+
homepage: ""
|
33
43
|
licenses: []
|
44
|
+
|
34
45
|
post_install_message:
|
35
46
|
rdoc_options: []
|
36
|
-
|
47
|
+
|
48
|
+
require_paths:
|
37
49
|
- lib
|
38
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
51
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
hash: 3
|
56
|
+
segments:
|
57
|
+
- 0
|
58
|
+
version: "0"
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
60
|
none: false
|
46
|
-
requirements:
|
47
|
-
- -
|
48
|
-
- !ruby/object:Gem::Version
|
49
|
-
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
50
68
|
requirements: []
|
69
|
+
|
51
70
|
rubyforge_project:
|
52
71
|
rubygems_version: 1.8.10
|
53
72
|
signing_key:
|
54
73
|
specification_version: 3
|
55
74
|
summary: Retry logic for rack-client
|
56
|
-
test_files:
|
75
|
+
test_files:
|
57
76
|
- spec/rack-idempotent_spec.rb
|
58
77
|
- spec/spec_helper.rb
|