right_support 2.10.1 → 2.11.2

Sign up to get free protection for your applications and to get access to all the features.
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'