redis_failover 0.9.2 → 0.9.3

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