Skip to content

Commit 230a5c4

Browse files
authored
Merge pull request #1227 from supercaracal/add-sharded-pubsub-support
Add sharded Pub/Sub support for cluster
2 parents ccdf15f + 54e6a7e commit 230a5c4

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

cluster/test/commands_on_pub_sub_test.rb

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,39 @@ def test_publish_psubscribe_punsubscribe_pubsub
7070
assert_equal('two', messages['gucci2'])
7171
assert_equal('three', messages['hermes3'])
7272
end
73+
74+
def test_spublish_ssubscribe_sunsubscribe_pubsub
75+
omit_version('7.0.0')
76+
77+
sub_cnt = 0
78+
messages = {}
79+
80+
thread = Thread.new do
81+
redis.ssubscribe('channel1', 'channel2') do |on|
82+
on.ssubscribe { sub_cnt += 1 }
83+
on.smessage do |c, msg|
84+
messages[c] = msg
85+
redis.sunsubscribe if messages.size == 2
86+
end
87+
end
88+
end
89+
90+
Thread.pass until sub_cnt == 2
91+
92+
publisher = build_another_client
93+
94+
assert_equal %w[channel1 channel2], publisher.pubsub(:shardchannels, 'channel*')
95+
assert_equal({ 'channel1' => 1, 'channel2' => 1, 'channel3' => 0 },
96+
publisher.pubsub(:shardnumsub, 'channel1', 'channel2', 'channel3'))
97+
98+
publisher.spublish('channel1', 'one')
99+
publisher.spublish('channel2', 'two')
100+
publisher.spublish('channel3', 'three')
101+
102+
thread.join
103+
104+
assert_equal(2, messages.size)
105+
assert_equal('one', messages['channel1'])
106+
assert_equal('two', messages['channel2'])
107+
end
73108
end

lib/redis/commands/pubsub.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,27 @@ def punsubscribe(*channels)
4949
def pubsub(subcommand, *args)
5050
send_command([:pubsub, subcommand] + args)
5151
end
52+
53+
# Post a message to a channel in a shard.
54+
def spublish(channel, message)
55+
send_command([:spublish, channel, message])
56+
end
57+
58+
# Listen for messages published to the given channels in a shard.
59+
def ssubscribe(*channels, &block)
60+
_subscription(:ssubscribe, 0, channels, block)
61+
end
62+
63+
# Listen for messages published to the given channels in a shard.
64+
# Throw a timeout error if there is no messages for a timeout period.
65+
def ssubscribe_with_timeout(timeout, *channels, &block)
66+
_subscription(:ssubscribe_with_timeout, timeout, channels, block)
67+
end
68+
69+
# Stop listening for messages posted to the given channels in a shard.
70+
def sunsubscribe(*channels)
71+
_subscription(:sunsubscribe, 0, channels, nil)
72+
end
5273
end
5374
end
5475
end

lib/redis/subscribe.rb

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@ def psubscribe_with_timeout(timeout, *channels, &block)
2929
subscription("psubscribe", "punsubscribe", channels, block, timeout)
3030
end
3131

32+
def ssubscribe(*channels, &block)
33+
subscription("ssubscribe", "sunsubscribe", channels, block)
34+
end
35+
36+
def ssubscribe_with_timeout(timeout, *channels, &block)
37+
subscription("ssubscribe", "sunsubscribe", channels, block, timeout)
38+
end
39+
3240
def unsubscribe(*channels)
3341
call_v([:unsubscribe, *channels])
3442
end
@@ -37,6 +45,10 @@ def punsubscribe(*channels)
3745
call_v([:punsubscribe, *channels])
3846
end
3947

48+
def sunsubscribe(*channels)
49+
call_v([:sunsubscribe, *channels])
50+
end
51+
4052
def close
4153
@client.close
4254
end
@@ -46,7 +58,11 @@ def close
4658
def subscription(start, stop, channels, block, timeout = 0)
4759
sub = Subscription.new(&block)
4860

49-
call_v([start, *channels])
61+
case start
62+
when "ssubscribe" then channels.each { |c| call_v([start, c]) } # avoid cross-slot keys
63+
else call_v([start, *channels])
64+
end
65+
5066
while event = @client.next_event(timeout)
5167
if event.is_a?(::RedisClient::CommandError)
5268
raise Client::ERROR_MAPPING.fetch(event.class), event.message
@@ -94,5 +110,17 @@ def punsubscribe(&block)
94110
def pmessage(&block)
95111
@callbacks["pmessage"] = block
96112
end
113+
114+
def ssubscribe(&block)
115+
@callbacks["ssubscribe"] = block
116+
end
117+
118+
def sunsubscribe(&block)
119+
@callbacks["sunsubscribe"] = block
120+
end
121+
122+
def smessage(&block)
123+
@callbacks["smessage"] = block
124+
end
97125
end
98126
end

0 commit comments

Comments
 (0)