redis_failover 0.5.3 → 0.5.4

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.5.4
2
+ -----------
3
+ - No longer use problematic ZK#reopen.
4
+
1
5
  0.5.3
2
6
  -----------
3
7
  - Handle more ZK exceptions as candidates for reconnecting the client on error.
@@ -109,37 +109,37 @@ module RedisFailover
109
109
  private
110
110
 
111
111
  def setup_zookeeper_client
112
- @zkclient = ZkClient.new(@zkservers)
113
- update_znode_timestamp
114
-
115
- # when session expires, purge client list
116
- @zkclient.on_session_expiration do
117
- purge_clients
118
- end
112
+ @zkclient = ZkClient.new(@zkservers) do |client|
113
+ # when session expires, purge client list
114
+ client.on_session_expiration do
115
+ purge_clients
116
+ end
119
117
 
120
- # when we are disconnected, purge client list
121
- @zkclient.event_handler.register_state_handler(:connecting) do
122
- purge_clients
123
- end
118
+ # when we are disconnected, purge client list
119
+ client.event_handler.register_state_handler(:connecting) do
120
+ purge_clients
121
+ end
124
122
 
125
- # when session is recovered, watch again
126
- @zkclient.on_session_recovered do
127
- @zkclient.stat(@znode, :watch => true)
128
- end
123
+ # when session is recovered, watch again
124
+ client.on_session_recovered do
125
+ client.stat(@znode, :watch => true)
126
+ end
129
127
 
130
- # register a watcher for future changes
131
- @zkclient.watcher.register(@znode) do |event|
132
- if event.node_created? || event.node_changed?
133
- update_znode_timestamp
134
- build_clients
135
- elsif event.node_deleted?
136
- update_znode_timestamp
137
- purge_clients
138
- @zkclient.stat(@znode, :watch => true)
139
- else
140
- logger.error("Unknown ZK node event: #{event.inspect}")
128
+ # register a watcher for future changes
129
+ client.watcher.register(@znode) do |event|
130
+ if event.node_created? || event.node_changed?
131
+ update_znode_timestamp
132
+ build_clients
133
+ elsif event.node_deleted?
134
+ update_znode_timestamp
135
+ purge_clients
136
+ client.stat(@znode, :watch => true)
137
+ else
138
+ logger.error("Unknown ZK node event: #{event.inspect}")
139
+ end
141
140
  end
142
141
  end
142
+ update_znode_timestamp
143
143
  end
144
144
 
145
145
  def redis_operation?(method)
@@ -177,8 +177,7 @@ module RedisFailover
177
177
  end
178
178
 
179
179
  def master
180
- master = @lock.synchronize { @master }
181
- if master
180
+ if master = @lock.synchronize { @master }
182
181
  verify_role!(master, :master)
183
182
  return master
184
183
  end
@@ -52,7 +52,7 @@ module RedisFailover
52
52
  perform_operation do |redis|
53
53
  unless slave_of?(master)
54
54
  redis.slaveof(master.host, master.port)
55
- logger.info("#{self} now a slave of master #{master}")
55
+ logger.info("#{self} is now a slave of master #{master}")
56
56
  wakeup
57
57
  end
58
58
  end
@@ -86,9 +86,9 @@ module RedisFailover
86
86
  def handle_syncing(node)
87
87
  reconcile(node)
88
88
 
89
- if node.prohibits_stale_reads?
89
+ if node.syncing_with_master? && node.prohibits_stale_reads?
90
90
  logger.info("Node #{node} not ready yet, still syncing with master.")
91
- @unavailable << node
91
+ force_unavailable_slave(node)
92
92
  return
93
93
  end
94
94
 
@@ -119,45 +119,46 @@ module RedisFailover
119
119
  nodes = @options[:nodes].map { |opts| Node.new(opts) }.uniq
120
120
  raise NoMasterError unless @master = find_master(nodes)
121
121
  @slaves = nodes - [@master]
122
+ logger.info("Managing master (#{@master}) and slaves" +
123
+ " (#{@slaves.map(&:to_s).join(', ')})")
122
124
 
123
125
  # ensure that slaves are correctly pointing to this master
124
126
  redirect_slaves_to_master
125
-
126
- logger.info("Managing master (#{@master}) and slaves" +
127
- " (#{@slaves.map(&:to_s).join(', ')})")
128
127
  end
129
128
 
130
129
  def spawn_watchers
131
- @watchers = [@master, *@slaves].map do |node|
130
+ @watchers = [@master, @slaves, @unavailable].flatten.map do |node|
132
131
  NodeWatcher.new(self, node, @options[:max_failures] || 3)
133
132
  end
134
133
  @watchers.each(&:watch)
135
134
  end
136
135
 
137
136
  def find_master(nodes)
138
- # try to find the master - if the actual master is currently
139
- # down, it will be handled by its watcher
140
137
  nodes.find do |node|
141
138
  begin
142
139
  node.master?
143
140
  rescue NodeUnavailableError
144
- # will eventually be handled by watcher
145
141
  false
146
142
  end
147
143
  end
148
144
  end
149
145
 
150
146
  def redirect_slaves_to_master
151
- # redirect each slave to the current master
152
- @slaves.each do |slave|
147
+ @slaves.dup.each do |slave|
153
148
  begin
154
149
  slave.make_slave!(@master)
155
150
  rescue NodeUnavailableError
156
- # will also be detected by watcher
151
+ logger.info("Failed to redirect unreachable slave #{slave} to master #{@master}")
152
+ force_unavailable_slave(slave)
157
153
  end
158
154
  end
159
155
  end
160
156
 
157
+ def force_unavailable_slave(node)
158
+ @slaves.delete(node)
159
+ @unavailable << node unless @unavailable.include?(node)
160
+ end
161
+
161
162
  # It's possible that a newly available node may have been restarted
162
163
  # and completely lost its dynamically set run-time role by the node
163
164
  # manager. This method ensures that the node resumes its role as
@@ -1,3 +1,3 @@
1
1
  module RedisFailover
2
- VERSION = "0.5.3"
2
+ VERSION = "0.5.4"
3
3
  end
@@ -15,9 +15,18 @@ module RedisFailover
15
15
  ZookeeperExceptions::ZookeeperException::ConnectionClosed,
16
16
  ZookeeperExceptions::ZookeeperException::NotConnected
17
17
  ].freeze
18
+ WRAPPED_ZK_METHODS = [
19
+ :get,
20
+ :set,
21
+ :watcher,
22
+ :event_handler,
23
+ :stat,
24
+ :create,
25
+ :delete].freeze
18
26
 
19
- def initialize(servers)
27
+ def initialize(servers, &setup_block)
20
28
  @servers = servers
29
+ @setup_block = setup_block
21
30
  @lock = Mutex.new
22
31
  build_client
23
32
  end
@@ -32,32 +41,14 @@ module RedisFailover
32
41
  @on_session_recovered = block
33
42
  end
34
43
 
35
- def get(*args, &block)
36
- perform_with_reconnect { @client.get(*args, &block) }
37
- end
38
-
39
- def set(*args, &block)
40
- perform_with_reconnect { @client.set(*args, &block) }
41
- end
42
-
43
- def watcher(*args, &block)
44
- perform_with_reconnect { @client.watcher(*args, &block) }
45
- end
46
-
47
- def event_handler(*args, &block)
48
- perform_with_reconnect { @client.event_handler(*args, &block) }
49
- end
50
-
51
- def stat(*args, &block)
52
- perform_with_reconnect { @client.stat(*args, &block) }
53
- end
54
-
55
- def create(*args, &block)
56
- perform_with_reconnect { @client.create(*args, &block) }
57
- end
58
-
59
- def delete(*args, &block)
60
- perform_with_reconnect { @client.delete(*args, &block) }
44
+ WRAPPED_ZK_METHODS.each do |zk_method|
45
+ class_eval <<-RUBY
46
+ def #{zk_method}(*args, &block)
47
+ perform_with_reconnect do
48
+ @client.#{zk_method}(*args, &block)
49
+ end
50
+ end
51
+ RUBY
61
52
  end
62
53
 
63
54
  private
@@ -83,11 +74,8 @@ module RedisFailover
83
74
 
84
75
  def build_client
85
76
  @lock.synchronize do
86
- if @client
87
- @client.reopen
88
- else
89
- @client = ZK.new(@servers)
90
- end
77
+ @client = ZK.new(@servers)
78
+ @setup_block.call(self) if @setup_block
91
79
  logger.info("Communicating with ZooKeeper servers #{@servers}")
92
80
  end
93
81
  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.5.3
4
+ version: 0.5.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2012-04-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
16
- requirement: &70306532639260 !ruby/object:Gem::Requirement
16
+ requirement: &70362366935580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70306532639260
24
+ version_requirements: *70362366935580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: redis-namespace
27
- requirement: &70306532638840 !ruby/object:Gem::Requirement
27
+ requirement: &70362366935160 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70306532638840
35
+ version_requirements: *70362366935160
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: multi_json
38
- requirement: &70306532638420 !ruby/object:Gem::Requirement
38
+ requirement: &70362366934740 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70306532638420
46
+ version_requirements: *70362366934740
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: zk
49
- requirement: &70306532638000 !ruby/object:Gem::Requirement
49
+ requirement: &70362366934320 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70306532638000
57
+ version_requirements: *70362366934320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rake
60
- requirement: &70306532637580 !ruby/object:Gem::Requirement
60
+ requirement: &70362366933900 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70306532637580
68
+ version_requirements: *70362366933900
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
- requirement: &70306532637160 !ruby/object:Gem::Requirement
71
+ requirement: &70362366933480 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,7 +76,7 @@ dependencies:
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70306532637160
79
+ version_requirements: *70362366933480
80
80
  description: Redis Failover is a ZooKeeper-based automatic master/slave failover solution
81
81
  for Ruby
82
82
  email:
@@ -129,7 +129,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
129
  version: '0'
130
130
  segments:
131
131
  - 0
132
- hash: -4476900958412029501
132
+ hash: 610999762978001666
133
133
  required_rubygems_version: !ruby/object:Gem::Requirement
134
134
  none: false
135
135
  requirements:
@@ -138,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  version: '0'
139
139
  segments:
140
140
  - 0
141
- hash: -4476900958412029501
141
+ hash: 610999762978001666
142
142
  requirements: []
143
143
  rubyforge_project:
144
144
  rubygems_version: 1.8.16