Skip to content

Commit

Permalink
Merge pull request #1255 from supercaracal/fix-cluster-tx
Browse files Browse the repository at this point in the history
Fix the watch command bugs for the cluster client
  • Loading branch information
byroot committed Apr 15, 2024
2 parents 8ab2753 + 65ac655 commit bce3f41
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 5 deletions.
4 changes: 4 additions & 0 deletions cluster/lib/redis/cluster.rb
Expand Up @@ -96,6 +96,10 @@ def cluster(subcommand, *args)
send_command([:cluster, subcommand] + args, &block)
end

def watch(*keys, &block)
synchronize { |c| c.call_v([:watch] + keys, &block) }
end

private

def initialize_client(options)
Expand Down
2 changes: 1 addition & 1 deletion cluster/redis-clustering.gemspec
Expand Up @@ -47,5 +47,5 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 2.7.0'

s.add_runtime_dependency('redis', s.version)
s.add_runtime_dependency('redis-cluster-client', '>= 0.7.0')
s.add_runtime_dependency('redis-cluster-client', '>= 0.7.11')
end
21 changes: 21 additions & 0 deletions cluster/test/client_transactions_test.rb
Expand Up @@ -48,4 +48,25 @@ def test_cluster_client_does_not_support_transaction_by_multiple_keys
assert_nil(redis.get("key#{i}"))
end
end

def test_cluster_client_does_support_transaction_with_optimistic_locking
redis.mset('{key}1', '1', '{key}2', '2')

another = Fiber.new do
cli = build_another_client
cli.mset('{key}1', '3', '{key}2', '4')
cli.close
Fiber.yield
end

redis.watch('{key}1', '{key}2') do |tx|
another.resume
v1 = redis.get('{key}1')
v2 = redis.get('{key}2')
tx.call('SET', '{key}1', v2)
tx.call('SET', '{key}2', v1)
end

assert_equal %w[3 4], redis.mget('{key}1', '{key}2')
end
end
25 changes: 22 additions & 3 deletions cluster/test/commands_on_transactions_test.rb
Expand Up @@ -38,10 +38,29 @@ def test_unwatch
end

def test_watch
assert_raises(Redis::CommandError, "CROSSSLOT Keys in request don't hash to the same slot") do
redis.watch('key1', 'key2')
assert_raises(Redis::Cluster::TransactionConsistencyError) do
redis.watch('{key}1', '{key}2')
end

assert_equal 'OK', redis.watch('{key}1', '{key}2')
assert_raises(Redis::Cluster::TransactionConsistencyError) do
redis.watch('key1', 'key2') do |tx|
tx.call('SET', 'key1', '1')
tx.call('SET', 'key2', '2')
end
end

assert_raises(Redis::Cluster::TransactionConsistencyError) do
redis.watch('{hey}1', '{hey}2') do |tx|
tx.call('SET', '{key}1', '1')
tx.call('SET', '{key}2', '2')
end
end

redis.watch('{key}1', '{key}2') do |tx|
tx.call('SET', '{key}1', '1')
tx.call('SET', '{key}2', '2')
end

assert_equal %w[1 2], redis.mget('{key}1', '{key}2')
end
end
2 changes: 1 addition & 1 deletion test/helper.rb
Expand Up @@ -174,7 +174,7 @@ def version
def with_acl
admin = _new_client
admin.acl('SETUSER', 'johndoe', 'on',
'+ping', '+select', '+command', '+cluster|slots', '+cluster|nodes',
'+ping', '+select', '+command', '+cluster|slots', '+cluster|nodes', '+readonly',
'>mysecret')
yield('johndoe', 'mysecret')
ensure
Expand Down

0 comments on commit bce3f41

Please sign in to comment.