Permalink
Browse files

Refactored redis server handling by extending Redis and Redis::Client…

… with convenient methods + watching new redis master after switch
  • Loading branch information...
1 parent db428b7 commit 7543694ac4a5345c2d57e90bf3685c6a74cce82e @boosty boosty committed May 26, 2010
Showing with 69 additions and 36 deletions.
  1. +2 −0 lib/beetle.rb
  2. +41 −36 lib/beetle/redis_configuration_server.rb
  3. +26 −0 lib/beetle/redis_ext.rb
View
@@ -36,6 +36,8 @@ class TwoRedisMasters < Error; end
Dir["#{lib_dir}/*.rb"].each do |libfile|
autoload File.basename(libfile)[/^(.*)\.rb$/, 1].classify, libfile
end
+
+ require "#{lib_dir}/redis_ext"
# returns the default configuration object and yields it if a block is given
def self.config
@@ -5,7 +5,6 @@ class RedisConfigurationServer
def start
logger.info "RedisConfigurationServer Starting"
RedisConfigurationClientMessageHandler.delegate_messages_to = self
- logger.info "Listening and watching"
beetle_client.listen do
redis_master_watcher.watch
end
@@ -29,17 +28,18 @@ def client_invalidated(payload)
# Method called from RedisWatcher
def redis_unavailable
- logger.warn "Redis master not available"
+ logger.warn "Redis master '#{redis_master.server}' not available"
# invalidate_current_master
# wait_for_invalidation_acknowledgements
if new_redis_master
- logger.warn "Setting new redis master to #{new_redis_master.server}"
- host = new_redis_master_host
- port = new_redis_master_port
- new_redis_master.slaveof("no one")
- @redis_master = Redis.new(:host => host, :port => port)
- logger.info "Publishing reconfigure message with host '#{host}' port '#{port}'"
- beetle_client.publish(:reconfigure, {:host => host, :port => port}.to_json)
+ logger.warn "Setting new redis master to '#{new_redis_master.server}'"
+ new_redis_master.master!
+ logger.info "Publishing reconfigure message with new host '#{new_redis_master.host}' port '#{new_redis_master.port}'"
+ beetle_client.publish(:reconfigure, {:host => new_redis_master.host, :port => new_redis_master.port}.to_json)
+ @redis_master = Redis.new(:host => new_redis_master.host, :port => new_redis_master.port)
+ @new_redis_master = nil
+ redis_master_watcher.redis = redis_master
+ redis_master_watcher.continue
else
logger.error "No redis slave available to become new master"
end
@@ -57,21 +57,35 @@ def process
end
class RedisWatcher
- def initialize(redis, watcher_delegate)
+ attr_accessor :redis, :pause
+
+ def initialize(redis, watcher_delegate, logger)
@redis = redis
@watcher_delegate = watcher_delegate
+ @logger = logger
+ @pause = false
end
def watch
timer = EventMachine::add_periodic_timer(1) {
+ return if @pause
+ @logger.debug "Watching redis '#{redis.server}'"
begin
@redis.info
rescue Exception
+ pause
@watcher_delegate.__send__(:redis_unavailable)
- timer.cancel
end
}
end
+
+ def pause
+ @pause = true
+ end
+
+ def continue
+ @pause = false
+ end
end
def beetle_client
@@ -98,42 +112,33 @@ def build_beetle_client
end
def redis_master_watcher
- @redis_master_watcher ||= RedisWatcher.new(redis_master, self)
+ @redis_master_watcher ||= RedisWatcher.new(redis_master, self, logger)
end
def redis_master
- @redis_master ||= find_initial_redis_master
- end
-
- def find_initial_redis_master
- all_available_redis.find{ |redis| redis.info["role"] == "master" }
- end
-
- def new_redis_master
- redis_slaves.first
- end
-
- def new_redis_master_host
- new_redis_master.server.split(":")[0]
+ @redis_master ||= initial_redis_master
end
-
- def new_redis_master_port
- new_redis_master.server.split(":")[1]
- end
-
- def redis_slaves
- all_available_redis.select{ |redis| redis.info["role"] == "slave" }
+
+ def initial_redis_master
+ all_available_redis.find{ |redis| redis.master? }
end
def all_available_redis
- all_redis.select{ |redis| redis.info rescue false }
+ all_redis.select{ |redis| redis.available? }
end
def all_redis
beetle_client.config.redis_hosts.split(",").map do |redis_host_string|
- host, port = redis_host_string.split(":")
- Redis.new(:host => host, :port => port) rescue nil
+ Redis.from_host_string(redis_host_string)
end
end
+
+ def new_redis_master
+ @new_redis_master ||= redis_slaves.first
+ end
+
+ def redis_slaves
+ all_available_redis.select{ |redis| redis.slave? }
+ end
end
-end
+end
View
@@ -0,0 +1,26 @@
+class Redis
+ def self.from_host_string(host_string)
+ host, port = host_string.split(':')
+ new(:host => host, :port => port)
+ end
+end
+
+class Redis::Client
+ attr_reader :host, :port
+
+ def available?
+ info rescue false
+ end
+
+ def master?
+ info["role"] == "master"
+ end
+
+ def slave?
+ info["role"] == "slave"
+ end
+
+ def master!
+ slaveof("no one")
+ end
+end

0 comments on commit 7543694

Please sign in to comment.