Skip to content

Commit 31c060c

Browse files
authored
Merge pull request rails#53845 from joshuay03/prevent-double-wrapped-redis-connection-pool-by-default
Don't wrap redis in `ConnectionPool` if already given one for `ActiveSupport::Cache::RedisCacheStore`
2 parents 58832ed + ffa9f3b commit 31c060c

File tree

4 files changed

+36
-10
lines changed

4 files changed

+36
-10
lines changed

activesupport/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* Avoid wrapping redis in a `ConnectionPool` when using `ActiveSupport::Cache::RedisCacheStore` if the `:redis`
2+
option is already a `ConnectionPool`.
3+
4+
*Joshua Young*
5+
16
* Alter `ERB::Util.tokenize` to return :PLAIN token with full input string when string doesn't contain ERB tags.
27

38
*Martin Emde*

activesupport/lib/active_support/cache.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ def retrieve_store_class(store)
186186
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
187187
#
188188
class Store
189+
# Default +ConnectionPool+ options
190+
DEFAULT_POOL_OPTIONS = { size: 5, timeout: 5 }.freeze
191+
189192
cattr_accessor :logger, instance_writer: true
190193
cattr_accessor :raise_on_invalid_cache_expiration_time, default: false
191194

@@ -194,9 +197,6 @@ class Store
194197

195198
class << self
196199
private
197-
DEFAULT_POOL_OPTIONS = { size: 5, timeout: 5 }.freeze
198-
private_constant :DEFAULT_POOL_OPTIONS
199-
200200
def retrieve_pool_options(options)
201201
if options.key?(:pool)
202202
pool_options = options.delete(:pool)

activesupport/lib/active_support/cache/redis_cache_store.rb

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,25 @@ def build_redis_client(**redis_options)
111111

112112
# Creates a new Redis cache store.
113113
#
114-
# There are four ways to provide the Redis client used by the cache: the
115-
# +:redis+ param can be a Redis instance or a block that returns a Redis
116-
# instance, or the +:url+ param can be a string or an array of strings
117-
# which will be used to create a Redis instance or a +Redis::Distributed+
118-
# instance.
114+
# There are a few ways to provide the Redis client used by the cache:
115+
#
116+
# 1. The +:redis+ param can be:
117+
# - A Redis instance.
118+
# - A +ConnectionPool+ instance wrapping a Redis instance.
119+
# - A block that returns a Redis instance.
120+
#
121+
# 2. The +:url+ param can be:
122+
# - A string used to create a Redis instance.
123+
# - An array of strings used to create a +Redis::Distributed+ instance.
124+
#
125+
# If the final Redis instance is not already a +ConnectionPool+, it will
126+
# be wrapped in one using +ActiveSupport::Cache::Store::DEFAULT_POOL_OPTIONS+.
127+
# These options can be overridden with the +:pool+ param, or the pool can be
128+
# disabled with +:pool: false+.
119129
#
120130
# Option Class Result
121-
# :redis Proc -> options[:redis].call
122131
# :redis Object -> options[:redis]
132+
# :redis Proc -> options[:redis].call
123133
# :url String -> Redis.new(url: …)
124134
# :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
125135
#
@@ -149,7 +159,8 @@ def build_redis_client(**redis_options)
149159
def initialize(error_handler: DEFAULT_ERROR_HANDLER, **redis_options)
150160
universal_options = redis_options.extract!(*UNIVERSAL_OPTIONS)
151161

152-
if pool_options = self.class.send(:retrieve_pool_options, redis_options)
162+
already_pool = redis_options[:redis].instance_of?(::ConnectionPool)
163+
if !already_pool && pool_options = self.class.send(:retrieve_pool_options, redis_options)
153164
@redis = ::ConnectionPool.new(pool_options) { self.class.build_redis(**redis_options) }
154165
else
155166
@redis = self.class.build_redis(**redis_options)

activesupport/test/cache/stores/redis_cache_store_test.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,16 @@ def test_connection_pooling_by_default
328328
assert_equal 5, pool.instance_variable_get(:@timeout)
329329
end
330330

331+
def test_no_connection_pooling_by_default_when_already_pool
332+
redis = ::ConnectionPool.new(size: 10, timeout: 2.5) { Redis.new }
333+
cache = ActiveSupport::Cache.lookup_store(:redis_cache_store, redis: redis)
334+
pool = cache.redis
335+
assert_kind_of ::ConnectionPool, pool
336+
assert_same redis, pool
337+
assert_equal 10, pool.size
338+
assert_equal 2.5, pool.instance_variable_get(:@timeout)
339+
end
340+
331341
private
332342
def store
333343
[:redis_cache_store]

0 commit comments

Comments
 (0)