Implement a connection pool for Redis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Implement a Redis Connection Pool | |
# | |
# Convenience methods | |
# Instead of having to write: | |
# redis_pool.perform {|redis| redis.get('key')} | |
# The following can be used | |
# redis_pool.get('key') | |
# | |
# This applies to all Redis methods except quit. RedisPool#quit calls quit | |
# on all instances of Redis already in the pool | |
# | |
# Dependencies: gene_pool | |
# | |
require 'gene_pool' | |
class RedisPool | |
# Each thread can request a Redis Connection and then return it once it is no | |
# longer needed by that thread. Rather than requesting a connection directly using | |
# Redis.new, pass a block so that the Redis connection | |
# is automatically returned to the pool. For example: | |
# redis_pool.perform do |redis| | |
# .. do something with the redis connection here | |
# end | |
# | |
# Parameters: | |
# see regular session parameters from: Redis.new | |
# | |
# Additional parameters for controlling the session pool itself | |
# :pool_name Name of the pool as it shows up in the logger. | |
# Default: 'RedisPool' | |
# :pool_size Maximum Pool Size. Default: 10 | |
# The pool only grows as needed and will never exceed | |
# :pool_size | |
# :pool_warn_timeout Amount of time to wait before logging a warning when a | |
# session in the pool is not available. Measured in seconds | |
# Default: 5.0 | |
# :pool_logger Supply a logger that responds to #debug, #info, #warn and #debug? | |
# For example: Rails.logger | |
# Default: None. | |
# Example: | |
# redis_pool = RedisPool.new(config) | |
# | |
# # Perform a single call to redis | |
# value = redis_pool.get('some_key') | |
# | |
# # Perform multiple calls using the same connection: | |
# redis_pool.perform do |redis| | |
# redis.set('some_key', 'Hello World') | |
# value = redis.get('some_key') | |
# end | |
def initialize(parms={}) | |
# Save Session parms since it will be used every time a new session is | |
# created in the pool | |
config = parms.dup | |
config[:logger] = SemanticLogger['Redis::Client'] | |
@pool = GenePool.new( | |
:name => parms[:pool_name] || self.class.name, | |
:pool_size => parms[:pool_size] || 10, | |
:warn_timeout => parms[:pool_warn_timeout] || 5, | |
:logger => parms[:pool_logger]) do | |
redis = Redis.new(config) | |
# Remove locking overhead since GenePool takes care of locking | |
redis.instance_eval("def synchronize\n yield(@client)\n end") | |
redis | |
end | |
end | |
# Obtain a Redis instance from the pool and pass it to the supplied block | |
# The session is automatically returned to the pool once the block completes | |
def perform(&block) | |
@pool.with_connection_auto_remove &block | |
end | |
# Quit all active Redis connections | |
def quit | |
@pool.each do |r| | |
r.quit | |
end | |
end | |
# Manually implement type since it is already implemented as a deprecated method | |
def type(key) | |
@pool.with_connection_auto_remove {|r| r.type(key)} | |
end | |
# Convenience methods | |
# Use with Care, multiple calls should rather be grouped into a single | |
# block using RedisPool#perform | |
# | |
# Obtain a Redis instance from the pool, call the matching redis method | |
# Return the Redis instance to the pool on completion | |
# | |
# Example: | |
# redis_pool = RedisPool.new(config) | |
# | |
# # Since we are only setting one key, we can use the shortcut | |
# redis_pool.set('some_key', 'Hello World') | |
# ..... | |
# value = redis_pool.get('some_key') | |
# .... | |
# # Release connections to Redis | |
# redis_pool.quit | |
(Redis.instance_methods - Object.methods).each do |method_name| | |
unless self.instance_methods.include? method_name | |
eval "def #{method_name}(*args)\n @pool.with_connection_auto_remove {|r| r.#{method_name}(*args)}\nend" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment