Skip to content

Commit 4ca5ad3

Browse files
authored
Only shutdown the Redis pool if it is owned by the SDK (#158)
* Only shutdown a Redis pool created by SDK * Make pool shutdown behavior an option
1 parent 07f7fc6 commit 4ca5ad3

File tree

4 files changed

+38
-4
lines changed

4 files changed

+38
-4
lines changed

lib/ldclient-rb/impl/integrations/redis_impl.rb

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ def initialize(opts)
3333
@pool = opts[:pool] || ConnectionPool.new(size: max_connections) do
3434
::Redis.new(@redis_opts)
3535
end
36+
# shutdown pool on close unless the client passed a custom pool and specified not to shutdown
37+
@pool_shutdown_on_close = (!opts[:pool] || opts.fetch(:pool_shutdown_on_close, true))
3638
@prefix = opts[:prefix] || LaunchDarkly::Integrations::Redis::default_prefix
3739
@logger = opts[:logger] || Config.default_logger
3840
@test_hook = opts[:test_hook] # used for unit tests, deliberately undocumented
@@ -118,6 +120,7 @@ def initialized_internal?
118120

119121
def stop
120122
if @stopped.make_true
123+
return unless @pool_shutdown_on_close
121124
@pool.shutdown { |redis| redis.close }
122125
end
123126
end

lib/ldclient-rb/integrations/redis.rb

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def self.default_prefix
4545
# @option opts [Integer] :expiration (15) expiration time for the in-memory cache, in seconds; 0 for no local caching
4646
# @option opts [Integer] :capacity (1000) maximum number of items in the cache
4747
# @option opts [Object] :pool custom connection pool, if desired
48+
# @option opts [Boolean] :pool_shutdown_on_close whether calling `close` should shutdown the custom connection pool.
4849
# @return [LaunchDarkly::Interfaces::FeatureStore] a feature store object
4950
#
5051
def self.new_feature_store(opts)

lib/ldclient-rb/redis_store.rb

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class RedisFeatureStore
3535
# @option opts [Integer] :expiration expiration time for the in-memory cache, in seconds; 0 for no local caching
3636
# @option opts [Integer] :capacity maximum number of feature flags (or related objects) to cache locally
3737
# @option opts [Object] :pool custom connection pool, if desired
38+
# @option opts [Boolean] :pool_shutdown_on_close whether calling `close` should shutdown the custom connection pool.
3839
#
3940
def initialize(opts = {})
4041
core = LaunchDarkly::Impl::Integrations::Redis::RedisFeatureStoreCore.new(opts)

spec/redis_feature_store_spec.rb

+33-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
require "connection_pool"
12
require "feature_store_spec_base"
23
require "json"
34
require "redis"
@@ -27,11 +28,11 @@ def clear_all_data
2728

2829
describe LaunchDarkly::RedisFeatureStore do
2930
subject { LaunchDarkly::RedisFeatureStore }
30-
31+
3132
break if ENV['LD_SKIP_DATABASE_TESTS'] == '1'
3233

3334
# These tests will all fail if there isn't a Redis instance running on the default port.
34-
35+
3536
context "real Redis with local cache" do
3637
include_examples "feature_store", method(:create_redis_store), method(:clear_all_data)
3738
end
@@ -59,7 +60,7 @@ def make_concurrent_modifier_test_hook(other_client, flag, start_version, end_ve
5960
flag = { key: "foo", version: 1 }
6061
test_hook = make_concurrent_modifier_test_hook(other_client, flag, 2, 4)
6162
store = create_redis_store({ test_hook: test_hook })
62-
63+
6364
begin
6465
store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
6566

@@ -77,7 +78,7 @@ def make_concurrent_modifier_test_hook(other_client, flag, start_version, end_ve
7778
flag = { key: "foo", version: 1 }
7879
test_hook = make_concurrent_modifier_test_hook(other_client, flag, 3, 3)
7980
store = create_redis_store({ test_hook: test_hook })
80-
81+
8182
begin
8283
store.init(LaunchDarkly::FEATURES => { flag[:key] => flag })
8384

@@ -89,4 +90,32 @@ def make_concurrent_modifier_test_hook(other_client, flag, start_version, end_ve
8990
other_client.close
9091
end
9192
end
93+
94+
it "shuts down a custom Redis pool by default" do
95+
unowned_pool = ConnectionPool.new(size: 1, timeout: 1) { Redis.new({ url: "redis://localhost:6379" }) }
96+
store = create_redis_store({ pool: unowned_pool })
97+
98+
begin
99+
store.init(LaunchDarkly::FEATURES => { })
100+
store.stop
101+
102+
expect { unowned_pool.with {} }.to raise_error(ConnectionPool::PoolShuttingDownError)
103+
ensure
104+
unowned_pool.shutdown { |conn| conn.close }
105+
end
106+
end
107+
108+
it "doesn't shut down a custom Redis pool if pool_shutdown_on_close = false" do
109+
unowned_pool = ConnectionPool.new(size: 1, timeout: 1) { Redis.new({ url: "redis://localhost:6379" }) }
110+
store = create_redis_store({ pool: unowned_pool, pool_shutdown_on_close: false })
111+
112+
begin
113+
store.init(LaunchDarkly::FEATURES => { })
114+
store.stop
115+
116+
expect { unowned_pool.with {} }.not_to raise_error(ConnectionPool::PoolShuttingDownError)
117+
ensure
118+
unowned_pool.shutdown { |conn| conn.close }
119+
end
120+
end
92121
end

0 commit comments

Comments
 (0)