rhod 0.1.2 → 0.1.3
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 +4 -4
- data/Changes.md +4 -0
- data/README.md +9 -1
- data/lib/rhod.rb +1 -0
- data/lib/rhod/command.rb +50 -29
- data/lib/rhod/middleware.rb +27 -4
- data/lib/rhod/profile.rb +15 -0
- data/lib/rhod/version.rb +1 -1
- data/rhod.gemspec +1 -1
- data/test/test_command.rb +70 -0
- data/test/test_middleware.rb +34 -0
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3800489cac9157423933e8c61a0d8de2e602ee4
|
4
|
+
data.tar.gz: 30424cdafb3aa4d099ef5983fdd391552119693f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 027c8d5951ce06f4fe47422dec3c46f1b4fccf8df72010ec27a608d1ff9d1ab762c7e721309bb765cdd44810e09332453edd5efb192447761e1f540e968181e2
|
7
|
+
data.tar.gz: 53921859dd5cd83d5e99d12b6c4d9e8ccf2ca6a790382f90ea169651532dca303d33ed83580de942bb4367b50a9246bb2ab75ababd1d246a575a9cd1b3db2f1b
|
data/Changes.md
CHANGED
data/README.md
CHANGED
@@ -95,7 +95,7 @@ Rhod.create_profile(:redis,
|
|
95
95
|
backoffs: :^,
|
96
96
|
pool: ConnectionPool.new(size: 3, timeout: 10) { Redis.new },
|
97
97
|
exceptions: [Redis::BaseError],
|
98
|
-
logger: Logger.new(
|
98
|
+
logger: Logger.new(STDOUT)
|
99
99
|
)
|
100
100
|
|
101
101
|
Rhod.with_redis("1") {|r, a| r.set('test',a)}
|
@@ -112,6 +112,14 @@ Code within a `Rhod::Command` block with reties in use must be _idempotent_, i.e
|
|
112
112
|
|
113
113
|
Code within a `Rhod::Command` should avoid leaking memory and/or scope by having arguments passed to it:
|
114
114
|
|
115
|
+
## Logging
|
116
|
+
|
117
|
+
Rhod can optionally log all failures, very useful for debugging. Just set a logger in a profile and they will be logged at the level `:warn`
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
Rhod.create_profile(:verbose, logger: Logger.new(STDOUT))
|
121
|
+
```
|
122
|
+
|
115
123
|
### Good use of argument passing:
|
116
124
|
|
117
125
|
```ruby
|
data/lib/rhod.rb
CHANGED
data/lib/rhod/command.rb
CHANGED
@@ -4,23 +4,19 @@ class Rhod::Command
|
|
4
4
|
|
5
5
|
def initialize(*args, &block)
|
6
6
|
opts = args[-1].kind_of?(Hash) ? args.pop : {}
|
7
|
-
@
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@pool = opts[:pool]
|
22
|
-
|
23
|
-
@exceptions = opts[:exceptions] || EXCEPTIONS
|
7
|
+
@env = {
|
8
|
+
:args => args || [],
|
9
|
+
:request => block,
|
10
|
+
:retries => opts[:retries] || 0,
|
11
|
+
:attempts => 0,
|
12
|
+
:logger => opts[:logger],
|
13
|
+
:backoffs => Rhod::Backoffs.backoff_sugar_to_enumerator(opts[:backoffs]) || Rhod::Backoffs::Logarithmic.new(1.3),
|
14
|
+
:fallback => opts[:fallback],
|
15
|
+
:pool => opts[:pool],
|
16
|
+
:exceptions => opts[:exceptions] || EXCEPTIONS,
|
17
|
+
:profile_name => opts[:profile_name],
|
18
|
+
:middleware => opts[:middleware_stack] || Rhod::Middleware.new,
|
19
|
+
}
|
24
20
|
end
|
25
21
|
|
26
22
|
### Class methods
|
@@ -34,26 +30,51 @@ class Rhod::Command
|
|
34
30
|
|
35
31
|
def execute
|
36
32
|
begin
|
37
|
-
if @pool
|
38
|
-
@pool.with do |conn|
|
39
|
-
@args = [conn].concat(@args)
|
33
|
+
if @env[:pool]
|
34
|
+
@env[:pool].with do |conn|
|
35
|
+
@env[:args] = [conn].concat(@env[:args])
|
40
36
|
|
41
|
-
|
37
|
+
call_middleware_before_request
|
38
|
+
@env[:result] = @env[:request].call(*@env[:args])
|
39
|
+
call_middleware_after_request
|
40
|
+
@env[:result]
|
42
41
|
end
|
43
42
|
else
|
44
|
-
|
43
|
+
call_middleware_before_request
|
44
|
+
@env[:result] = @env[:request].call(*@env[:args])
|
45
|
+
call_middleware_after_request
|
46
|
+
@env[:result]
|
45
47
|
end
|
46
|
-
rescue *@exceptions => e
|
47
|
-
@attempts += 1
|
48
|
-
@next_attempt = @backoffs.next
|
49
|
-
if @attempts <= @retries
|
50
|
-
@logger.warn("Rhod - Caught an exception: #{e.message}. Attempt #{@attempts} in #{sprintf("%.2f", @next_attempt)} secs") if @logger && @logger.respond_to?(:warn)
|
51
|
-
|
48
|
+
rescue *@env[:exceptions] => e
|
49
|
+
@env[:attempts] += 1
|
50
|
+
@env[:next_attempt] = @env[:backoffs].next
|
51
|
+
if @env[:attempts] <= @env[:retries]
|
52
|
+
@env[:logger].warn("Rhod - Caught an exception: #{e.message}. Attempt #{@env[:attempts]} in #{sprintf("%.2f", @env[:next_attempt])} secs") if @env[:logger] && @env[:logger].respond_to?(:warn)
|
53
|
+
call_middleware_on_error
|
54
|
+
sleep(@env[:next_attempt])
|
52
55
|
retry
|
53
56
|
else
|
54
|
-
|
57
|
+
call_middleware_on_failure
|
58
|
+
return @env[:fallback].call(*@env[:args]) if @env[:fallback]
|
55
59
|
raise
|
56
60
|
end
|
57
61
|
end
|
58
62
|
end
|
63
|
+
|
64
|
+
def call_middleware_before_request
|
65
|
+
@env = @env[:middleware].on(:before, @env)
|
66
|
+
end
|
67
|
+
|
68
|
+
def call_middleware_after_request
|
69
|
+
@env = @env[:middleware].on(:after, @env)
|
70
|
+
end
|
71
|
+
|
72
|
+
def call_middleware_on_error
|
73
|
+
@env = @env[:middleware].on(:error, @env)
|
74
|
+
end
|
75
|
+
|
76
|
+
def call_middleware_on_failure
|
77
|
+
@env = @env[:middleware].on(:failure, @env)
|
78
|
+
end
|
79
|
+
|
59
80
|
end
|
data/lib/rhod/middleware.rb
CHANGED
@@ -1,10 +1,33 @@
|
|
1
1
|
class Rhod::Middleware
|
2
|
+
class Rhod::InvalidMiddleware < Exception; end
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@stack = []
|
6
|
+
end
|
7
|
+
|
2
8
|
def use(middleware, *args, &block)
|
3
|
-
|
9
|
+
@stack << [middleware, args, block]
|
4
10
|
end
|
5
11
|
|
6
|
-
|
7
|
-
|
8
|
-
|
12
|
+
def build_stack
|
13
|
+
@stack = @stack.map do |current_middleware|
|
14
|
+
klass, args, block = current_middleware
|
15
|
+
|
16
|
+
if klass.is_a?(Class)
|
17
|
+
klass.new(*args, &block)
|
18
|
+
else
|
19
|
+
raise Rhod::InvalidMiddleware, "Unable to call middleware #{current_middleware}"
|
20
|
+
end
|
21
|
+
end
|
9
22
|
end
|
23
|
+
|
24
|
+
def on(event, env)
|
25
|
+
@stack.reduce(env) do |e, current_middleware|
|
26
|
+
if current_middleware.respond_to?(:on)
|
27
|
+
e = current_middleware.on(event, e)
|
28
|
+
end
|
29
|
+
e
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
10
33
|
end
|
data/lib/rhod/profile.rb
CHANGED
@@ -13,6 +13,21 @@ class Rhod::Profile < Hash
|
|
13
13
|
|
14
14
|
options.each {|k,v| self[k] = v }
|
15
15
|
|
16
|
+
self[:profile_name] = name
|
17
|
+
|
18
|
+
# Middleware stack construction
|
19
|
+
self[:middleware_stack] = Rhod::Middleware.new
|
20
|
+
|
21
|
+
if self[:middleware].respond_to?(:call)
|
22
|
+
self[:middleware].call(self[:middleware_stack])
|
23
|
+
elsif self[:middleware]
|
24
|
+
self[:middleware].each do |klass|
|
25
|
+
self[:middleware_stack].use klass
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
self[:middleware_stack].build_stack
|
30
|
+
|
16
31
|
# Syntax sugar: named .with_#{profile} methods on this class and the module
|
17
32
|
@@profiles[name] = self
|
18
33
|
|
data/lib/rhod/version.rb
CHANGED
data/rhod.gemspec
CHANGED
data/test/test_command.rb
CHANGED
@@ -96,7 +96,77 @@ describe Rhod::Command do
|
|
96
96
|
pool = ConnectionPool.new(size: 1, timeout: 0) { :conn }
|
97
97
|
Rhod::Command.new(1, pool: pool) {|a, b| [a,b]}.execute.must_equal [:conn, 1]
|
98
98
|
end
|
99
|
+
|
100
|
+
describe "with middleware" do
|
101
|
+
it "triggers the before and after event" do
|
102
|
+
pool = ConnectionPool.new(size: 1, timeout: 0) { :conn }
|
103
|
+
|
104
|
+
@stack = MiniTest::Mock.new
|
105
|
+
|
106
|
+
cmd = Rhod::Command.new(
|
107
|
+
middleware_stack: @stack,
|
108
|
+
pool: pool
|
109
|
+
) {|a| a}
|
110
|
+
env = cmd.instance_eval {@env}
|
111
|
+
@stack.expect :on, env, [:before, Hash]
|
112
|
+
@stack.expect :on, env, [:after, Hash]
|
113
|
+
cmd.execute
|
114
|
+
@stack.verify
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
describe "with middleware" do
|
122
|
+
it "triggers the before and after event" do
|
123
|
+
@stack = MiniTest::Mock.new
|
124
|
+
cmd = Rhod::Command.new(middleware_stack: @stack) {|a| a}
|
125
|
+
env = cmd.instance_eval {@env}
|
126
|
+
@stack.expect :on, env, [:before, Hash]
|
127
|
+
@stack.expect :on, env, [:after, Hash]
|
128
|
+
cmd.execute
|
129
|
+
@stack.verify
|
130
|
+
end
|
131
|
+
|
132
|
+
it "triggers the failure event" do
|
133
|
+
@stack = MiniTest::Mock.new
|
134
|
+
cmd = Rhod::Command.new(middleware_stack: @stack) do
|
135
|
+
raise StandardError, "Problem"
|
136
|
+
end
|
137
|
+
env = cmd.instance_eval {@env}
|
138
|
+
@stack.expect :on, env, [:before, Hash]
|
139
|
+
@stack.expect :on, env, [:failure, Hash]
|
140
|
+
|
141
|
+
begin
|
142
|
+
cmd.execute
|
143
|
+
rescue
|
144
|
+
end
|
145
|
+
|
146
|
+
@stack.verify
|
147
|
+
end
|
148
|
+
|
149
|
+
it "triggers the error event" do
|
150
|
+
@stack = MiniTest::Mock.new
|
151
|
+
cmd = Rhod::Command.new(
|
152
|
+
middleware_stack: @stack,
|
153
|
+
retries: 1) do
|
154
|
+
raise StandardError, "Problem"
|
155
|
+
end
|
156
|
+
env = cmd.instance_eval {@env}
|
157
|
+
@stack.expect :on, env, [:before, Hash]
|
158
|
+
@stack.expect :on, env, [:error, Hash]
|
159
|
+
@stack.expect :on, env, [:failure, Hash]
|
160
|
+
|
161
|
+
begin
|
162
|
+
cmd.execute
|
163
|
+
rescue
|
164
|
+
end
|
165
|
+
|
166
|
+
@stack.verify
|
167
|
+
end
|
99
168
|
end
|
100
169
|
|
170
|
+
|
101
171
|
end
|
102
172
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/helper')
|
3
|
+
|
4
|
+
class TestMiddleware
|
5
|
+
def initialize(params=nil)
|
6
|
+
@opts = params
|
7
|
+
end
|
8
|
+
|
9
|
+
def on(event, env)
|
10
|
+
env
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Rhod::Middleware do
|
15
|
+
it "inits with args passed in" do
|
16
|
+
stack = Rhod::Middleware.new
|
17
|
+
|
18
|
+
stack.use(TestMiddleware, 1)
|
19
|
+
stack.build_stack
|
20
|
+
|
21
|
+
stack.instance_eval{@stack}.first.instance_eval{@opts}.must_equal 1
|
22
|
+
end
|
23
|
+
|
24
|
+
it "calls each callback correctly" do
|
25
|
+
%I[before after error failure].each do |event|
|
26
|
+
stack = Rhod::Middleware.new
|
27
|
+
|
28
|
+
stack.use(TestMiddleware)
|
29
|
+
stack.build_stack
|
30
|
+
|
31
|
+
stack.send(:on, event, output: 0)[:output].must_equal 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhod
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Bergeron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - ~>
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 1.
|
89
|
+
version: 1.1.0
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ~>
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 1.
|
96
|
+
version: 1.1.0
|
97
97
|
description:
|
98
98
|
email:
|
99
99
|
- paul.d.bergeron@gmail.com
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- test/helper.rb
|
124
124
|
- test/test_backoffs.rb
|
125
125
|
- test/test_command.rb
|
126
|
+
- test/test_middleware.rb
|
126
127
|
- test/test_profile.rb
|
127
128
|
homepage: https://github.com/dinedal/rhod
|
128
129
|
licenses:
|
@@ -144,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
145
|
version: '0'
|
145
146
|
requirements: []
|
146
147
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.0.
|
148
|
+
rubygems_version: 2.0.2
|
148
149
|
signing_key:
|
149
150
|
specification_version: 4
|
150
151
|
summary: A High Avalibility framework for Ruby
|
@@ -152,4 +153,6 @@ test_files:
|
|
152
153
|
- test/helper.rb
|
153
154
|
- test/test_backoffs.rb
|
154
155
|
- test/test_command.rb
|
156
|
+
- test/test_middleware.rb
|
155
157
|
- test/test_profile.rb
|
158
|
+
has_rdoc:
|