redis_failover 0.9.2 → 0.9.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.
data/Changes.md CHANGED
@@ -1,3 +1,7 @@
1
+ 0.9.3
2
+ -----------
3
+ - Add lock assert for Node Manager.
4
+
1
5
  0.9.2
2
6
  -----------
3
7
  - Improved exception handling in NodeWatcher.
@@ -11,6 +11,12 @@ module RedisFailover
11
11
 
12
12
  # Number of seconds to wait before retrying bootstrap process.
13
13
  TIMEOUT = 5
14
+ # ZK Errors that the Node Manager cares about.
15
+ ZK_ERRORS = [
16
+ ZK::Exceptions::LockAssertionFailedError,
17
+ ZK::Exceptions::InterruptedSession,
18
+ ZKDisconnectedError
19
+ ].freeze
14
20
 
15
21
  # Creates a new instance.
16
22
  #
@@ -26,6 +32,7 @@ module RedisFailover
26
32
  @znode = @options[:znode_path] || Util::DEFAULT_ZNODE_PATH
27
33
  @manual_znode = ManualFailover::ZNODE_PATH
28
34
  @mutex = Mutex.new
35
+ @shutdown = false
29
36
 
30
37
  # Name for the znode that handles exclusive locking between multiple
31
38
  # Node Manager processes. Whoever holds the lock will be considered
@@ -40,11 +47,12 @@ module RedisFailover
40
47
  #
41
48
  # @note This method does not return until the manager terminates.
42
49
  def start
50
+ return if @shutdown
43
51
  @queue = Queue.new
44
52
  @leader = false
45
53
  setup_zk
46
54
  logger.info('Waiting to become master Node Manager ...')
47
- @zk.with_lock(@lock_path) do
55
+ with_lock do
48
56
  @leader = true
49
57
  logger.info('Acquired master Node Manager lock')
50
58
  discover_nodes
@@ -52,9 +60,8 @@ module RedisFailover
52
60
  spawn_watchers
53
61
  handle_state_reports
54
62
  end
55
- rescue ZK::Exceptions::InterruptedSession, ZKDisconnectedError => ex
63
+ rescue *ZK_ERRORS => ex
56
64
  logger.error("ZK error while attempting to manage nodes: #{ex.inspect}")
57
- logger.error(ex.backtrace.join("\n"))
58
65
  shutdown
59
66
  sleep(TIMEOUT)
60
67
  retry
@@ -71,10 +78,12 @@ module RedisFailover
71
78
 
72
79
  # Performs a graceful shutdown of the manager.
73
80
  def shutdown
81
+ @shutdown = true
74
82
  @queue.clear
75
83
  @queue << nil
76
84
  @watchers.each(&:shutdown) if @watchers
77
85
  @zk.close! if @zk
86
+ @zk_lock = nil
78
87
  end
79
88
 
80
89
  private
@@ -106,7 +115,10 @@ module RedisFailover
106
115
 
107
116
  # Handles periodic state reports from {RedisFailover::NodeWatcher} instances.
108
117
  def handle_state_reports
109
- while state_report = @queue.pop
118
+ while running? && (state_report = @queue.pop)
119
+ # Ensure that we still have the master lock.
120
+ @zk_lock.assert!
121
+
110
122
  begin
111
123
  node, state = state_report
112
124
  case state
@@ -120,7 +132,7 @@ module RedisFailover
120
132
 
121
133
  # flush current state
122
134
  write_state
123
- rescue ZK::Exceptions::InterruptedSession, ZKDisconnectedError
135
+ rescue *ZK_ERRORS
124
136
  # fail hard if this is a ZK connection-related error
125
137
  raise
126
138
  rescue => ex
@@ -155,7 +167,7 @@ module RedisFailover
155
167
  reconcile(node)
156
168
 
157
169
  # no-op if we already know about this node
158
- return if @master == node || @slaves.include?(node)
170
+ return if @master == node || (@master && @slaves.include?(node))
159
171
  logger.info("Handling available node: #{node}")
160
172
 
161
173
  if @master
@@ -343,6 +355,15 @@ module RedisFailover
343
355
  @zk.set(@znode, encode(current_nodes))
344
356
  end
345
357
 
358
+ # Executes a block wrapped in a ZK exclusive lock.
359
+ def with_lock
360
+ @zk_lock = @zk.locker(@lock_path)
361
+ @zk_lock.lock(true)
362
+ yield
363
+ ensure
364
+ @zk_lock.unlock! if @zk_lock
365
+ end
366
+
346
367
  # Schedules a manual failover to a redis node.
347
368
  def schedule_manual_failover
348
369
  return unless @leader
@@ -364,5 +385,10 @@ module RedisFailover
364
385
  logger.error('Failed to perform manual failover, no candidate found.')
365
386
  end
366
387
  end
388
+
389
+ # @return [Boolean] true if still running, false otherwise
390
+ def running?
391
+ !@shutdown
392
+ end
367
393
  end
368
394
  end
@@ -1,3 +1,3 @@
1
1
  module RedisFailover
2
- VERSION = '0.9.2'
2
+ VERSION = '0.9.3'
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.2
4
+ version: 0.9.3
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-27 00:00:00.000000000 Z
12
+ date: 2012-08-29 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: -3297653838576069671
192
+ hash: -1811569102428626424
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: -3297653838576069671
201
+ hash: -1811569102428626424
202
202
  requirements: []
203
203
  rubyforge_project:
204
204
  rubygems_version: 1.8.23