redis_failover 0.9.3 → 0.9.4

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.
data/Changes.md CHANGED
@@ -1,3 +1,8 @@
1
+ 0.9.4
2
+ -----------
3
+ - Preserve original master by reading from existing znode state.
4
+ - Prevent Timeout::Error from bringing down the process (#32) (@eric)
5
+
1
6
  0.9.3
2
7
  -----------
3
8
  - Add lock assert for Node Manager.
@@ -175,13 +175,13 @@ module RedisFailover
175
175
  redis = new_client
176
176
  yield redis
177
177
  end
178
- rescue => ex
178
+ rescue Exception => ex
179
179
  raise NodeUnavailableError, "#{ex.class}: #{ex.message}", ex.backtrace
180
180
  ensure
181
181
  if redis
182
182
  begin
183
183
  redis.client.disconnect
184
- rescue => ex
184
+ rescue Exception => ex
185
185
  raise NodeUnavailableError, "#{ex.class}: #{ex.message}", ex.backtrace
186
186
  end
187
187
  end
@@ -10,7 +10,7 @@ module RedisFailover
10
10
  include Util
11
11
 
12
12
  # Number of seconds to wait before retrying bootstrap process.
13
- TIMEOUT = 5
13
+ TIMEOUT = 3
14
14
  # ZK Errors that the Node Manager cares about.
15
15
  ZK_ERRORS = [
16
16
  ZK::Exceptions::LockAssertionFailedError,
@@ -32,7 +32,6 @@ module RedisFailover
32
32
  @znode = @options[:znode_path] || Util::DEFAULT_ZNODE_PATH
33
33
  @manual_znode = ManualFailover::ZNODE_PATH
34
34
  @mutex = Mutex.new
35
- @shutdown = false
36
35
 
37
36
  # Name for the znode that handles exclusive locking between multiple
38
37
  # Node Manager processes. Whoever holds the lock will be considered
@@ -47,7 +46,6 @@ module RedisFailover
47
46
  #
48
47
  # @note This method does not return until the manager terminates.
49
48
  def start
50
- return if @shutdown
51
49
  @queue = Queue.new
52
50
  @leader = false
53
51
  setup_zk
@@ -63,7 +61,6 @@ module RedisFailover
63
61
  rescue *ZK_ERRORS => ex
64
62
  logger.error("ZK error while attempting to manage nodes: #{ex.inspect}")
65
63
  shutdown
66
- sleep(TIMEOUT)
67
64
  retry
68
65
  end
69
66
 
@@ -78,10 +75,10 @@ module RedisFailover
78
75
 
79
76
  # Performs a graceful shutdown of the manager.
80
77
  def shutdown
81
- @shutdown = true
82
78
  @queue.clear
83
79
  @queue << nil
84
80
  @watchers.each(&:shutdown) if @watchers
81
+ sleep(TIMEOUT)
85
82
  @zk.close! if @zk
86
83
  @zk_lock = nil
87
84
  end
@@ -115,7 +112,7 @@ module RedisFailover
115
112
 
116
113
  # Handles periodic state reports from {RedisFailover::NodeWatcher} instances.
117
114
  def handle_state_reports
118
- while running? && (state_report = @queue.pop)
115
+ while state_report = @queue.pop
119
116
  # Ensure that we still have the master lock.
120
117
  @zk_lock.assert!
121
118
 
@@ -238,9 +235,9 @@ module RedisFailover
238
235
 
239
236
  # Discovers the current master and slave nodes.
240
237
  def discover_nodes
241
- @unavailable = []
242
238
  nodes = @options[:nodes].map { |opts| Node.new(opts) }.uniq
243
- @master = find_master(nodes)
239
+ @master = find_existing_master || find_master(nodes)
240
+ @unavailable = []
244
241
  @slaves = nodes - [@master]
245
242
  logger.info("Managing master (#{@master}) and slaves" +
246
243
  " (#{@slaves.map(&:to_s).join(', ')})")
@@ -249,9 +246,32 @@ module RedisFailover
249
246
  redirect_slaves_to(@master) if @master
250
247
  end
251
248
 
249
+ # Seeds the initial node master from an existing znode config.
250
+ def find_existing_master
251
+ if data = @zk.get(@znode).first
252
+ nodes = symbolize_keys(decode(data))
253
+ master = node_from(nodes[:master])
254
+ logger.info("Master from existing config: #{master || 'none'}")
255
+ master
256
+ end
257
+ rescue ZK::Exceptions::NoNode
258
+ # blank slate, no last known master
259
+ nil
260
+ end
261
+
262
+ # Creates a Node instance from a string.
263
+ #
264
+ # @param [String] node_string a string representation of a node (e.g., host:port)
265
+ # @return [Node] the Node representation
266
+ def node_from(node_string)
267
+ return if node_string.nil?
268
+ host, port = node_string.split(':', 2)
269
+ Node.new(:host => host, :port => port, :password => @options[:password])
270
+ end
271
+
252
272
  # Spawns the {RedisFailover::NodeWatcher} instances for each managed node.
253
273
  def spawn_watchers
254
- @watchers = [@master, @slaves, @unavailable].flatten.map do |node|
274
+ @watchers = [@master, @slaves, @unavailable].flatten.compact.map do |node|
255
275
  NodeWatcher.new(self, node, @options[:max_failures] || 3)
256
276
  end
257
277
  @watchers.each(&:watch)
@@ -385,10 +405,5 @@ module RedisFailover
385
405
  logger.error('Failed to perform manual failover, no candidate found.')
386
406
  end
387
407
  end
388
-
389
- # @return [Boolean] true if still running, false otherwise
390
- def running?
391
- !@shutdown
392
- end
393
408
  end
394
409
  end
@@ -66,7 +66,7 @@ module RedisFailover
66
66
  notify(:unavailable)
67
67
  failures = 0
68
68
  end
69
- rescue => ex
69
+ rescue Exception => ex
70
70
  logger.error("Unexpected error while monitoring node #{@node}: #{ex.inspect}")
71
71
  logger.error(ex.backtrace.join("\n"))
72
72
  end
@@ -1,3 +1,3 @@
1
1
  module RedisFailover
2
- VERSION = '0.9.3'
2
+ VERSION = '0.9.4'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_failover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
4
+ version: 0.9.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-29 00:00:00.000000000 Z
12
+ date: 2012-08-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -189,7 +189,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
189
189
  version: '0'
190
190
  segments:
191
191
  - 0
192
- hash: -1811569102428626424
192
+ hash: -3042115734438994013
193
193
  required_rubygems_version: !ruby/object:Gem::Requirement
194
194
  none: false
195
195
  requirements:
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  version: '0'
199
199
  segments:
200
200
  - 0
201
- hash: -1811569102428626424
201
+ hash: -3042115734438994013
202
202
  requirements: []
203
203
  rubyforge_project:
204
204
  rubygems_version: 1.8.23