2012-10-14 16:54:34 -07:00
require 'connection_pool'
2012-03-31 12:45:24 -07:00
require 'redis'
2013-11-17 10:20:28 -05:00
require 'uri'
2012-02-08 16:43:57 -06:00
module Sidekiq
class RedisConnection
2013-04-17 10:07:46 -07:00
class << self
2012-04-06 09:43:02 -07:00
2013-04-17 10:07:46 -07:00
def create ( options = { } )
2015-04-05 03:17:13 +03:00
options [ :url ] || = determine_redis_provider
2013-11-24 08:16:37 -06:00
2015-10-30 08:43:56 -07:00
size = options [ :size ] || ( Sidekiq . server? ? ( Sidekiq . options [ :concurrency ] + 5 ) : 5 )
2013-04-17 10:07:46 -07:00
2015-10-20 21:25:03 -07:00
verify_sizing ( size , Sidekiq . options [ :concurrency ] ) if Sidekiq . server?
pool_timeout = options [ :pool_timeout ] || 1
2013-10-21 20:28:38 +02:00
log_info ( options )
2013-04-17 10:07:46 -07:00
2013-07-17 09:02:51 -06:00
ConnectionPool . new ( :timeout = > pool_timeout , :size = > size ) do
2013-10-21 20:28:38 +02:00
build_client ( options )
2013-04-17 10:07:46 -07:00
end
end
private
2015-10-20 21:25:03 -07:00
# Sidekiq needs a lot of concurrent Redis connections.
#
# We need a connection for each Processor.
# We need a connection for Pro's real-time change listener
# We need a connection to various features to call Redis every few seconds:
# - the process heartbeat.
# - enterprise's leader election
# - enterprise's cron support
def verify_sizing ( size , concurrency )
raise ArgumentError , " Your Redis connection pool is too small for Sidekiq to work, your pool has #{ size } connections but really needs to have at least #{ concurrency + 2 } " if size < = concurrency
end
2013-10-21 20:28:38 +02:00
def build_client ( options )
namespace = options [ :namespace ]
client = Redis . new client_opts ( options )
2013-04-17 10:07:46 -07:00
if namespace
2015-10-20 21:25:03 -07:00
begin
require 'redis/namespace'
Redis :: Namespace . new ( namespace , :redis = > client )
rescue LoadError
2016-01-29 20:12:39 +01:00
Sidekiq . logger . error ( " Your Redis configuration use the namespace ' #{ namespace } ' but the redis-namespace gem not included in Gemfile. " \
" Add the gem to your Gemfile in case you would like to keep using a namespace, otherwise remove the namespace parameter. " )
2015-10-20 21:25:03 -07:00
exit ( - 127 )
end
2013-04-17 10:07:46 -07:00
else
client
end
end
2013-10-21 20:28:38 +02:00
def client_opts ( options )
2013-10-21 21:36:51 +02:00
opts = options . dup
if opts [ :namespace ]
opts . delete ( :namespace )
2013-07-17 09:02:51 -06:00
end
2013-10-21 20:28:38 +02:00
2013-10-21 21:36:51 +02:00
if opts [ :network_timeout ]
opts [ :timeout ] = opts [ :network_timeout ]
opts . delete ( :network_timeout )
2013-10-21 20:28:38 +02:00
end
2013-10-21 21:36:51 +02:00
opts [ :driver ] = opts [ :driver ] || 'ruby'
2013-10-21 20:28:38 +02:00
2013-10-21 21:36:51 +02:00
opts
2013-07-17 09:02:51 -06:00
end
2013-10-21 20:28:38 +02:00
def log_info ( options )
2013-11-17 10:20:28 -05:00
# Don't log Redis AUTH password
2014-06-20 01:12:53 -07:00
redacted = " REDACTED "
2013-11-17 10:20:28 -05:00
scrubbed_options = options . dup
if scrubbed_options [ :url ] && ( uri = URI . parse ( scrubbed_options [ :url ] ) ) && uri . password
2014-06-20 01:12:53 -07:00
uri . password = redacted
2013-11-17 10:20:28 -05:00
scrubbed_options [ :url ] = uri . to_s
end
2014-06-20 01:12:53 -07:00
if scrubbed_options [ :password ]
scrubbed_options [ :password ] = redacted
end
2013-04-17 10:07:46 -07:00
if Sidekiq . server?
2013-11-17 10:20:28 -05:00
Sidekiq . logger . info ( " Booting Sidekiq #{ Sidekiq :: VERSION } with redis options #{ scrubbed_options } " )
2013-04-17 10:07:46 -07:00
else
2014-06-21 21:01:59 -07:00
Sidekiq . logger . debug ( " #{ Sidekiq :: NAME } client with redis options #{ scrubbed_options } " )
2013-04-17 10:07:46 -07:00
end
2013-04-17 09:53:01 -07:00
end
2013-04-17 10:07:46 -07:00
def determine_redis_provider
2014-02-01 20:49:04 -08:00
ENV [ ENV [ 'REDIS_PROVIDER' ] || 'REDIS_URL' ]
2012-03-13 21:19:46 -07:00
end
2012-02-08 16:43:57 -06:00
2012-10-14 14:58:20 -07:00
end
2012-02-08 16:43:57 -06:00
end
end