Skip to content

Commit e268a51

Browse files
authored
feat: introduce max_startup_sample in ClusterConfig (#369)
2 parents 628276b + dea9cc7 commit e268a51

File tree

4 files changed

+31
-8
lines changed

4 files changed

+31
-8
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ gem 'redis-cluster-client'
3030
| `:slow_command_timeout` | Integer | `-1` | timeout used for "slow" queries that fetch metdata e.g. CLUSTER NODES, COMMAND |
3131
| `:concurrency` | Hash | `{ model: :on_demand, size: 5}` | concurrency settings, `:on_demand`, `:pooled` and `:none` are valid models, size is a max number of workers, `:none` model is no concurrency, Please choose the one suited your environment if needed. |
3232
| `:connect_with_original_config` | Boolean | `false` | `true` if client should retry the connection using the original endpoint that was passed in |
33+
| `:max_startup_sample` | Integer | `3` | maximum number of nodes to fetch `CLUSTER NODES` information for startup |
3334

3435
Also, [the other generic options](https://github.com/redis-rb/redis-client#configuration) can be passed.
3536
But `:url`, `:host`, `:port` and `:path` are ignored because they conflict with the `:nodes` option.

lib/redis_client/cluster/node.rb

+1-4
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ class Cluster
1313
class Node
1414
include Enumerable
1515

16-
# It affects to strike a balance between load and stability in initialization or changed states.
17-
MAX_STARTUP_SAMPLE = Integer(ENV.fetch('REDIS_CLIENT_MAX_STARTUP_SAMPLE', 3))
18-
1916
# less memory consumption, but slow
2017
USE_CHAR_ARRAY_SLOT = Integer(ENV.fetch('REDIS_CLIENT_USE_CHAR_ARRAY_SLOT', 1)) == 1
2118

@@ -197,7 +194,7 @@ def update_slot(slot, node_key)
197194

198195
def reload!
199196
with_reload_lock do
200-
with_startup_clients(MAX_STARTUP_SAMPLE) do |startup_clients|
197+
with_startup_clients(@config.max_startup_sample) do |startup_clients|
201198
@node_info = refetch_node_info_list(startup_clients)
202199
@node_configs = @node_info.to_h do |node_info|
203200
[node_info.node_key, @config.client_config_for_node(node_info.node_key)]

lib/redis_client/cluster_config.rb

+6-2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ class ClusterConfig
2020
MAX_WORKERS = Integer(ENV.fetch('REDIS_CLIENT_MAX_THREADS', 5))
2121
# It's used with slow queries of fetching meta data like CLUSTER NODES, COMMAND and so on.
2222
SLOW_COMMAND_TIMEOUT = Float(ENV.fetch('REDIS_CLIENT_SLOW_COMMAND_TIMEOUT', -1))
23+
# It affects to strike a balance between load and stability in initialization or changed states.
24+
MAX_STARTUP_SAMPLE = Integer(ENV.fetch('REDIS_CLIENT_MAX_STARTUP_SAMPLE', 3))
2325

2426
InvalidClientConfigError = Class.new(::RedisClient::Error)
2527

2628
attr_reader :command_builder, :client_config, :replica_affinity, :slow_command_timeout,
27-
:connect_with_original_config, :startup_nodes
29+
:connect_with_original_config, :startup_nodes, :max_startup_sample
2830

29-
def initialize(
31+
def initialize( # rubocop:disable Metrics/ParameterLists
3032
nodes: DEFAULT_NODES,
3133
replica: false,
3234
replica_affinity: :random,
@@ -36,6 +38,7 @@ def initialize(
3638
client_implementation: ::RedisClient::Cluster, # for redis gem
3739
slow_command_timeout: SLOW_COMMAND_TIMEOUT,
3840
command_builder: ::RedisClient::CommandBuilder,
41+
max_startup_sample: MAX_STARTUP_SAMPLE,
3942
**client_config
4043
)
4144

@@ -51,6 +54,7 @@ def initialize(
5154
@connect_with_original_config = connect_with_original_config
5255
@client_implementation = client_implementation
5356
@slow_command_timeout = slow_command_timeout
57+
@max_startup_sample = max_startup_sample
5458
end
5559

5660
def inspect

test/redis_client/cluster/test_node.rb

+23-2
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ def test_reload
600600

601601
# It should have reloaded by calling CLUSTER NODES on three of the startup nodes
602602
cluster_node_cmds = capture_buffer.to_a.select { |c| c.command == %w[CLUSTER NODES] }
603-
assert_equal RedisClient::Cluster::Node::MAX_STARTUP_SAMPLE, cluster_node_cmds.size
603+
assert_equal RedisClient::ClusterConfig::MAX_STARTUP_SAMPLE, cluster_node_cmds.size
604604

605605
# It should have connected to all of the clients.
606606
assert_equal TEST_NUMBER_OF_NODES, test_node.to_a.size
@@ -635,6 +635,27 @@ def test_reload_with_original_config
635635
assert_equal bootstrap_node, cluster_node_cmds.first.server_url
636636
end
637637

638+
def test_reload_with_overriden_sample_size
639+
capture_buffer = CommandCaptureMiddleware::CommandBuffer.new
640+
test_node = make_node(replica: true, capture_buffer: capture_buffer, max_startup_sample: 1)
641+
642+
capture_buffer.clear
643+
test_node.reload!
644+
645+
# It should have reloaded by calling CLUSTER NODES on one of the startup nodes
646+
cluster_node_cmds = capture_buffer.to_a.select { |c| c.command == %w[CLUSTER NODES] }
647+
assert_equal 1, cluster_node_cmds.size
648+
649+
# It should have connected to all of the clients.
650+
assert_equal TEST_NUMBER_OF_NODES, test_node.to_a.size
651+
652+
# If we reload again, it should NOT change the redis client instances we have.
653+
original_client_ids = test_node.to_a.map(&:object_id).to_set
654+
test_node.reload!
655+
new_client_ids = test_node.to_a.map(&:object_id).to_set
656+
assert_equal original_client_ids, new_client_ids
657+
end
658+
638659
def test_reload_concurrently
639660
capture_buffer = CommandCaptureMiddleware::CommandBuffer.new
640661
test_node = make_node(replica: true, pool: { size: 2 }, capture_buffer: capture_buffer)
@@ -656,7 +677,7 @@ def refetch_node_info_list(...)
656677
# We should only have reloaded once, which is to say, we only called CLUSTER NODES command MAX_STARTUP_SAMPLE
657678
# times
658679
cluster_node_cmds = capture_buffer.to_a.select { |c| c.command == %w[CLUSTER NODES] }
659-
assert_equal RedisClient::Cluster::Node::MAX_STARTUP_SAMPLE, cluster_node_cmds.size
680+
assert_equal RedisClient::ClusterConfig::MAX_STARTUP_SAMPLE, cluster_node_cmds.size
660681
end
661682
end
662683
# rubocop:enable Metrics/ClassLength

0 commit comments

Comments
 (0)