right_support 2.10.1 → 2.11.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45713709a34db9049a788ea3bd6e371bc9cdcb2c
4
- data.tar.gz: 9ae79e61f4b120b3bdc15c03da6df873d8bed016
3
+ metadata.gz: 169232720914f75758ba15e8bb1b14864c143226
4
+ data.tar.gz: a7a1d9eb7ba2a0686ee2ddc0a5839a0d4ede6166
5
5
  SHA512:
6
- metadata.gz: b4eef7bc6bc87bcd4c275935533be46b4f222291fce03e48a995595c952d0d8116cba0ce6fe1769ec660b3ec92536a112aa3008a40a4283c4f9a4ea4d9c2017a
7
- data.tar.gz: 5074d0f87841daa8df2a59dfcf4f9ca0e724ee0c9cdc1748ebe07719b1fa7e513722e8bb24b92eb4aee3047c44d5fe45cf553bd5d3c24411ecd89ceb200ec84c
6
+ metadata.gz: 57e4fd72803654f3e772cebe5c9f4a22066067dac8926b507edcadad35931ddebf9fd51a33916dbd06a27abae561144e075b840d77c9a4bd1e37286c4d1b26b1
7
+ data.tar.gz: ca11d752bb148b96d426f228d23215b7a751d26df821d1e43f8be7200b7a71fb395f18df9640d02d276b7642787a89b26cdb8fc173e6cb047073994cb0d03a38
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.10.1
1
+ 2.11.2
@@ -0,0 +1,51 @@
1
+ #
2
+ # Copyright (c) 2016 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'digest/md5'
24
+
25
+ module RightSupport::Data
26
+
27
+ # unique token generator. short tokens that are friendler than raw UUIDs for
28
+ # logging purposes, etc.
29
+ class Token
30
+
31
+ # exact length of all generated tokens.
32
+ TOKEN_LENGTH = 13
33
+
34
+ # Generate new token
35
+ #
36
+ # @return [String] token
37
+ def self.generate
38
+ # MD5 is 128bit = 25 chars in base 36, need to fit in less
39
+ # The code below produces a 64 bit value evenly distributed.
40
+ i = ::Digest::MD5.hexdigest(::RightSupport::Data::UUID.generate).to_i(16)
41
+ t = ((i >> 64) ^ (i & 0xFFFFFFFFFFFFFFFF)).to_s(36)
42
+
43
+ # left-pad with zeros to keep token length consistant.
44
+ if t.length < TOKEN_LENGTH
45
+ t = '0' * (TOKEN_LENGTH - t.length) + t
46
+ end
47
+ t
48
+ end
49
+
50
+ end
51
+ end
@@ -34,3 +34,4 @@ require 'right_support/data/serializer'
34
34
  require 'right_support/data/hash_tools'
35
35
  require 'right_support/data/uuid'
36
36
  require 'right_support/data/mash'
37
+ require 'right_support/data/token'
@@ -0,0 +1,96 @@
1
+ #
2
+ # Copyright (c) 2016 RightScale Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ module RightSupport::Net::LB
24
+
25
+ # base class for load balancer policies.
26
+ class Base
27
+
28
+ # @param [Hash] options provided for derived policies
29
+ def initialize(options = {})
30
+ @options = options.dup
31
+ @endpoints = []
32
+ @counter = rand(0xffff)
33
+
34
+ # note that not all policies require health-checking but the request
35
+ # balancer will provide the callback by default.
36
+ @health_check = @options.delete(:health_check)
37
+ if @health_check && !@health_check.respond_to?(:call)
38
+ raise ::ArgumentError, ':health_check is invalid.'
39
+ end
40
+ end
41
+
42
+ # override only if endpoint selection is non-trivial
43
+ def set_endpoints(endpoints)
44
+ @endpoints = endpoints
45
+ true
46
+ end
47
+
48
+ # override only if endpoint selection is non-trivial
49
+ def next
50
+ result = nil
51
+ unless @endpoints.empty?
52
+ # endpoint, no health-check required.
53
+ result = [ @endpoints[@counter % @endpoints.size], false ]
54
+ @counter += 1
55
+ end
56
+ result
57
+ end
58
+
59
+ # override only if statisics are kept
60
+ #
61
+ # @return [TrueClass] always true
62
+ def good(endpoint, t0, t1)
63
+ true
64
+ end
65
+
66
+ # override only if statisics are kept
67
+ #
68
+ # @return [TrueClass] always true
69
+ def bad(endpoint, t0, t1)
70
+ true
71
+ end
72
+
73
+ # performs a basic health-check for given endpoint using functor and updates
74
+ # statistics, if kept.
75
+ #
76
+ # @param [String] endpoint for check
77
+ #
78
+ # @return [TrueClass] always true
79
+ def health_check(endpoint)
80
+ t0 = ::Time.now
81
+ result = @health_check.call(endpoint)
82
+ t1 = ::Time.now
83
+ if result
84
+ good(endpoint, t0, t1)
85
+ return true
86
+ end
87
+ bad(endpoint, t0, t1)
88
+ return false
89
+ rescue ::Exception
90
+ t1 = ::Time.now
91
+ bad(endpoint, t0, t1)
92
+ raise
93
+ end
94
+
95
+ end
96
+ end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2011 RightScale Inc
2
+ # Copyright (c) 2011-2016 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -89,9 +89,10 @@ module RightSupport::Net::LB
89
89
  # Returns a hash of endpoints and their colored health status
90
90
  # Useful for logging and debugging
91
91
  def get_stats
92
- stats = {}
93
- @endpoints.each { |k, v| stats[k] = state_color(v[:n_level]) }
94
- stats
92
+ @endpoints.inject({}) do |stats, (k, v)|
93
+ stats[k] = state_color(v[:n_level])
94
+ stats
95
+ end
95
96
  end
96
97
 
97
98
  # Replace the set of endpoints that this object knows about. If any
@@ -129,71 +130,46 @@ module RightSupport::Net::LB
129
130
  # reported on the way back down, e.g., yellow is reported as soon as the first endpoint
130
131
  # transitions from red to yellow, and so on.
131
132
 
132
- class HealthCheck
133
+ class HealthCheck < ::RightSupport::Net::LB::Base
133
134
  include RightSupport::Log::Mixin
134
135
 
135
136
  def initialize(options = {})
136
- @options = options
137
+ super
138
+ @stack = nil
137
139
  end
138
140
 
139
141
  def set_endpoints(endpoints)
140
142
  if @stack
141
143
  @stack.update!(endpoints)
142
144
  else
143
- @health_check = @options.delete(:health_check)
144
- @counter = Process.pid
145
- @last_size = endpoints.size
146
145
  @stack = EndpointsStack.new(self, endpoints, @options[:yellow_states], @options[:reset_time], @options[:on_health_change])
147
146
  end
147
+ true
148
148
  end
149
149
 
150
150
  def next
151
- # Returns the array of hashes which consists of yellow and green endpoints with the
152
- # following structure: [ [EP1, {:n_level => ..., :timestamp => ... }], [EP2, ... ] ]
153
- endpoints = @stack.sweep_and_return_yellow_and_green
154
- return nil if endpoints.empty?
155
-
156
- # From the available set, use a RoundRobin-like algorithm to select the next endpoint.
157
- # When the size of the available set changes, try not to disturb our index into the list.
158
- @counter += 1 unless endpoints.size < @last_size
159
- @counter %= endpoints.size
160
- @last_size = endpoints.size
161
-
162
- # Hash#select returns a Hash in ruby1.9, but an Array of pairs in ruby1.8.
163
- # This should really be encapsulated in EndpointsStack...
164
- if RUBY_VERSION >= '1.9'
165
- key = endpoints.keys[@counter]
166
- next_endpoint = [ key, endpoints[key][:n_level] != 0 ]
167
- else
168
- next_endpoint = [ endpoints[@counter][0], endpoints[@counter][1][:n_level] != 0 ]
151
+ # avoid red endpoints until they timeout, which may leave us with none
152
+ # temporarily. the idea is to have multiple endpoints such that one or
153
+ # more can go down while others continue to respond.
154
+ result = nil
155
+ yg_eps = @stack.sweep_and_return_yellow_and_green
156
+ unless yg_eps.empty?
157
+ @endpoints = yg_eps.keys
158
+ if result = super
159
+ result[1] = yg_eps[result[0]][:n_level] != 0
160
+ end
169
161
  end
170
-
171
- next_endpoint
162
+ result
172
163
  end
173
164
 
174
165
  def good(endpoint, t0, t1)
175
166
  @stack.decrease_state(endpoint, t0, t1)
167
+ true
176
168
  end
177
169
 
178
170
  def bad(endpoint, t0, t1)
179
171
  @stack.increase_state(endpoint, t0, t1)
180
- end
181
-
182
- def health_check(endpoint)
183
- t0 = Time.now
184
- result = @health_check.call(endpoint)
185
- t1 = Time.now
186
- if result
187
- @stack.decrease_state(endpoint, t0, t1)
188
- return true
189
- else
190
- @stack.increase_state(endpoint, t0, t1)
191
- return false
192
- end
193
- rescue Exception => e
194
- t1 = Time.now
195
- @stack.increase_state(endpoint, t0, t1)
196
- raise
172
+ true
197
173
  end
198
174
 
199
175
  # Proxy to EndpointStack
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2011 RightScale Inc
2
+ # Copyright (c) 2011-2016 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -21,32 +21,14 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
 
23
23
  module RightSupport::Net::LB
24
- class RoundRobin
24
+ class RoundRobin < ::RightSupport::Net::LB::Base
25
25
 
26
- def initialize(options ={})
27
- @endpoints = []
28
- @counter = rand(0xffff)
29
- end
30
-
31
- def set_endpoints(endpoints)
32
- @endpoints = endpoints
33
- end
34
-
35
- def next
36
- @counter += 1
37
- [ @endpoints[@counter % @endpoints.size], false ] unless @endpoints.empty?
38
- end
39
-
40
- def good(endpoint, t0, t1)
41
- #no-op; round robin does not care about failures
42
- end
43
-
44
- def bad(endpoint, t0, t1)
45
- #no-op; round robin does not care about failures
26
+ def initialize(options = {})
27
+ super
46
28
  end
47
29
 
48
30
  def health_check(endpoint)
49
- #no-op; round robin does not perform health checks
31
+ # no-op; round robin does not perform health checks
50
32
  true
51
33
  end
52
34
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2011 RightScale Inc
2
+ # Copyright (c) 2011-2016 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -29,52 +29,35 @@ module RightSupport::Net::LB
29
29
  # - re-iterate through each endpoint when it's endpoint loses validity;
30
30
  # - return an Exception if it performs a complete iteration though each endpoint and finds none valid;
31
31
 
32
- class Sticky
32
+ class Sticky < ::RightSupport::Net::LB::Base
33
33
 
34
34
  def initialize(options = {})
35
- @health_check = options.delete(:health_check)
36
- @endpoints = []
37
- @counter = rand(0xffff)
35
+ super
38
36
  end
39
37
 
40
38
  def set_endpoints(endpoints)
41
39
  unless @endpoints.empty?
42
- last_chosen = self.next.first
40
+ last_chosen = @endpoints[@counter % @endpoints.size]
43
41
  @endpoints = []
44
42
  if endpoints.include?(last_chosen)
45
43
  @endpoints << last_chosen
46
44
  @counter = 0
47
45
  end
48
46
  end
49
- @endpoints |= endpoints
47
+ @endpoints |= endpoints # a union of endpoints
48
+ true
50
49
  end
51
50
 
52
51
  def next
52
+ # note that counter is not incremented here; hence stickyness.
53
53
  [ @endpoints[@counter % @endpoints.size], false ] unless @endpoints.empty?
54
54
  end
55
55
 
56
- def good(endpoint, t0, t1)
57
- #no-op; round robin does not care about failures
58
- end
59
-
60
56
  def bad(endpoint, t0, t1)
57
+ # increment from bad endpoint index to unstick. this is only meaningful if
58
+ # there are multiple endpoints.
61
59
  @counter += 1
62
- end
63
-
64
- def health_check(endpoint)
65
- t0 = Time.now
66
- result = @health_check.call(endpoint)
67
- t1 = Time.now
68
- if result
69
- return true
70
- else
71
- @counter += 1
72
- return false
73
- end
74
- rescue Exception => e
75
- t1 = Time.now
76
- @counter += 1
77
- raise
60
+ nil
78
61
  end
79
62
 
80
63
  end
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2011 RightScale Inc
2
+ # Copyright (c) 2011-2016 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -28,6 +28,7 @@ module RightSupport::Net::LB
28
28
 
29
29
  end
30
30
 
31
+ require 'right_support/net/lb/base'
31
32
  require 'right_support/net/lb/health_check'
32
33
  require 'right_support/net/lb/round_robin'
33
34
  require 'right_support/net/lb/sticky'