redis 4.1.1 → 4.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +69 -0
- data/README.md +24 -5
- data/lib/redis/client.rb +71 -73
- data/lib/redis/cluster/node.rb +3 -0
- data/lib/redis/cluster/node_key.rb +3 -7
- data/lib/redis/cluster/option.rb +27 -14
- data/lib/redis/cluster/slot.rb +30 -13
- data/lib/redis/cluster/slot_loader.rb +4 -4
- data/lib/redis/cluster.rb +13 -4
- data/lib/redis/connection/command_helper.rb +3 -2
- data/lib/redis/connection/hiredis.rb +4 -3
- data/lib/redis/connection/registry.rb +2 -1
- data/lib/redis/connection/ruby.rb +118 -103
- data/lib/redis/connection/synchrony.rb +9 -4
- data/lib/redis/connection.rb +2 -0
- data/lib/redis/distributed.rb +117 -62
- data/lib/redis/errors.rb +2 -0
- data/lib/redis/hash_ring.rb +15 -14
- data/lib/redis/pipeline.rb +16 -3
- data/lib/redis/subscribe.rb +11 -12
- data/lib/redis/version.rb +3 -1
- data/lib/redis.rb +394 -354
- metadata +15 -25
data/lib/redis/distributed.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative "hash_ring"
|
2
4
|
|
3
5
|
class Redis
|
4
6
|
class Distributed
|
5
|
-
|
6
7
|
class CannotDistribute < RuntimeError
|
7
8
|
def initialize(command)
|
8
9
|
@command = command
|
9
10
|
end
|
10
11
|
|
11
12
|
def message
|
12
|
-
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need
|
13
|
+
"#{@command.to_s.upcase} cannot be used in Redis::Distributed because the keys involved need " \
|
14
|
+
"to be on the same server or because we cannot guarantee that the operation will be atomic."
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -22,10 +24,14 @@ class Redis
|
|
22
24
|
@default_options = options.dup
|
23
25
|
node_configs.each { |node_config| add_node(node_config) }
|
24
26
|
@subscribed_node = nil
|
27
|
+
@watch_key = nil
|
25
28
|
end
|
26
29
|
|
27
30
|
def node_for(key)
|
28
|
-
|
31
|
+
key = key_tag(key.to_s) || key.to_s
|
32
|
+
raise CannotDistribute, :watch if @watch_key && @watch_key != key
|
33
|
+
|
34
|
+
@ring.get_node(key)
|
29
35
|
end
|
30
36
|
|
31
37
|
def nodes
|
@@ -33,9 +39,9 @@ class Redis
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def add_node(options)
|
36
|
-
options = { :
|
42
|
+
options = { url: options } if options.is_a?(String)
|
37
43
|
options = @default_options.merge(options)
|
38
|
-
@ring.add_node Redis.new(
|
44
|
+
@ring.add_node Redis.new(options)
|
39
45
|
end
|
40
46
|
|
41
47
|
# Change the selected database for the current connection.
|
@@ -144,12 +150,12 @@ class Redis
|
|
144
150
|
end
|
145
151
|
|
146
152
|
# Create a key using the serialized value, previously obtained using DUMP.
|
147
|
-
def restore(key, ttl, serialized_value, options
|
148
|
-
node_for(key).restore(key, ttl, serialized_value, options)
|
153
|
+
def restore(key, ttl, serialized_value, **options)
|
154
|
+
node_for(key).restore(key, ttl, serialized_value, **options)
|
149
155
|
end
|
150
156
|
|
151
157
|
# Transfer a key from the connected instance to another instance.
|
152
|
-
def migrate(
|
158
|
+
def migrate(_key, _options)
|
153
159
|
raise CannotDistribute, :migrate
|
154
160
|
end
|
155
161
|
|
@@ -170,8 +176,33 @@ class Redis
|
|
170
176
|
end
|
171
177
|
|
172
178
|
# Determine if a key exists.
|
173
|
-
def exists(
|
174
|
-
|
179
|
+
def exists(*args)
|
180
|
+
if !Redis.exists_returns_integer && args.size == 1
|
181
|
+
message = "`Redis#exists(key)` will return an Integer in redis-rb 4.3, if you want to keep the old behavior, " \
|
182
|
+
"use `exists?` instead. To opt-in to the new behavior now you can set Redis.exists_returns_integer = true. " \
|
183
|
+
"(#{::Kernel.caller(1, 1).first})\n"
|
184
|
+
|
185
|
+
if defined?(::Warning)
|
186
|
+
::Warning.warn(message)
|
187
|
+
else
|
188
|
+
warn(message)
|
189
|
+
end
|
190
|
+
exists?(*args)
|
191
|
+
else
|
192
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
193
|
+
keys_per_node.inject(0) do |sum, (node, keys)|
|
194
|
+
sum + node._exists(*keys)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
# Determine if any of the keys exists.
|
200
|
+
def exists?(*args)
|
201
|
+
keys_per_node = args.group_by { |key| node_for(key) }
|
202
|
+
keys_per_node.each do |node, keys|
|
203
|
+
return true if node.exists?(*keys)
|
204
|
+
end
|
205
|
+
false
|
175
206
|
end
|
176
207
|
|
177
208
|
# Find all keys matching the given pattern.
|
@@ -204,11 +235,11 @@ class Redis
|
|
204
235
|
end
|
205
236
|
|
206
237
|
# Sort the elements in a list, set or sorted set.
|
207
|
-
def sort(key, options
|
238
|
+
def sort(key, **options)
|
208
239
|
keys = [key, options[:by], options[:store], *Array(options[:get])].compact
|
209
240
|
|
210
241
|
ensure_same_node(:sort, keys) do |node|
|
211
|
-
node.sort(key, options)
|
242
|
+
node.sort(key, **options)
|
212
243
|
end
|
213
244
|
end
|
214
245
|
|
@@ -243,8 +274,8 @@ class Redis
|
|
243
274
|
end
|
244
275
|
|
245
276
|
# Set the string value of a key.
|
246
|
-
def set(key, value, options
|
247
|
-
node_for(key).set(key, value, options)
|
277
|
+
def set(key, value, **options)
|
278
|
+
node_for(key).set(key, value, **options)
|
248
279
|
end
|
249
280
|
|
250
281
|
# Set the time to live in seconds of a key.
|
@@ -263,20 +294,20 @@ class Redis
|
|
263
294
|
end
|
264
295
|
|
265
296
|
# Set multiple keys to multiple values.
|
266
|
-
def mset(*
|
297
|
+
def mset(*_args)
|
267
298
|
raise CannotDistribute, :mset
|
268
299
|
end
|
269
300
|
|
270
|
-
def mapped_mset(
|
301
|
+
def mapped_mset(_hash)
|
271
302
|
raise CannotDistribute, :mapped_mset
|
272
303
|
end
|
273
304
|
|
274
305
|
# Set multiple keys to multiple values, only if none of the keys exist.
|
275
|
-
def msetnx(*
|
306
|
+
def msetnx(*_args)
|
276
307
|
raise CannotDistribute, :msetnx
|
277
308
|
end
|
278
309
|
|
279
|
-
def mapped_msetnx(
|
310
|
+
def mapped_msetnx(_hash)
|
280
311
|
raise CannotDistribute, :mapped_msetnx
|
281
312
|
end
|
282
313
|
|
@@ -335,7 +366,7 @@ class Redis
|
|
335
366
|
end
|
336
367
|
|
337
368
|
# Return the position of the first bit set to 1 or 0 in a string.
|
338
|
-
def bitpos(key, bit, start=nil, stop=nil)
|
369
|
+
def bitpos(key, bit, start = nil, stop = nil)
|
339
370
|
node_for(key).bitpos(key, bit, start, stop)
|
340
371
|
end
|
341
372
|
|
@@ -353,7 +384,7 @@ class Redis
|
|
353
384
|
get(key)
|
354
385
|
end
|
355
386
|
|
356
|
-
def []=(key,value)
|
387
|
+
def []=(key, value)
|
357
388
|
set(key, value)
|
358
389
|
end
|
359
390
|
|
@@ -401,13 +432,12 @@ class Redis
|
|
401
432
|
end
|
402
433
|
|
403
434
|
def _bpop(cmd, args)
|
404
|
-
|
405
|
-
|
406
|
-
if args.last.is_a?(Hash)
|
435
|
+
timeout = if args.last.is_a?(Hash)
|
407
436
|
options = args.pop
|
437
|
+
options[:timeout]
|
408
438
|
elsif args.last.respond_to?(:to_int)
|
409
439
|
# Issue deprecation notice in obnoxious mode...
|
410
|
-
|
440
|
+
args.pop.to_int
|
411
441
|
end
|
412
442
|
|
413
443
|
if args.size > 1
|
@@ -417,7 +447,11 @@ class Redis
|
|
417
447
|
keys = args.flatten
|
418
448
|
|
419
449
|
ensure_same_node(cmd, keys) do |node|
|
420
|
-
|
450
|
+
if timeout
|
451
|
+
node.__send__(cmd, keys, timeout: timeout)
|
452
|
+
else
|
453
|
+
node.__send__(cmd, keys)
|
454
|
+
end
|
421
455
|
end
|
422
456
|
end
|
423
457
|
|
@@ -435,15 +469,9 @@ class Redis
|
|
435
469
|
|
436
470
|
# Pop a value from a list, push it to another list and return it; or block
|
437
471
|
# until one is available.
|
438
|
-
def brpoplpush(source, destination,
|
439
|
-
case options
|
440
|
-
when Integer
|
441
|
-
# Issue deprecation notice in obnoxious mode...
|
442
|
-
options = { :timeout => options }
|
443
|
-
end
|
444
|
-
|
472
|
+
def brpoplpush(source, destination, deprecated_timeout = 0, **options)
|
445
473
|
ensure_same_node(:brpoplpush, [source, destination]) do |node|
|
446
|
-
node.brpoplpush(source, destination, options)
|
474
|
+
node.brpoplpush(source, destination, deprecated_timeout, **options)
|
447
475
|
end
|
448
476
|
end
|
449
477
|
|
@@ -520,13 +548,13 @@ class Redis
|
|
520
548
|
end
|
521
549
|
|
522
550
|
# Scan a set
|
523
|
-
def sscan(key, cursor, options
|
524
|
-
node_for(key).sscan(key, cursor, options)
|
551
|
+
def sscan(key, cursor, **options)
|
552
|
+
node_for(key).sscan(key, cursor, **options)
|
525
553
|
end
|
526
554
|
|
527
555
|
# Scan a set and return an enumerator
|
528
|
-
def sscan_each(key, options
|
529
|
-
node_for(key).sscan_each(key, options, &block)
|
556
|
+
def sscan_each(key, **options, &block)
|
557
|
+
node_for(key).sscan_each(key, **options, &block)
|
530
558
|
end
|
531
559
|
|
532
560
|
# Subtract multiple sets.
|
@@ -581,6 +609,7 @@ class Redis
|
|
581
609
|
def zadd(key, *args)
|
582
610
|
node_for(key).zadd(key, *args)
|
583
611
|
end
|
612
|
+
ruby2_keywords(:zadd) if respond_to?(:ruby2_keywords, true)
|
584
613
|
|
585
614
|
# Increment the score of a member in a sorted set.
|
586
615
|
def zincrby(key, increment, member)
|
@@ -598,14 +627,14 @@ class Redis
|
|
598
627
|
end
|
599
628
|
|
600
629
|
# Return a range of members in a sorted set, by index.
|
601
|
-
def zrange(key, start, stop, options
|
602
|
-
node_for(key).zrange(key, start, stop, options)
|
630
|
+
def zrange(key, start, stop, **options)
|
631
|
+
node_for(key).zrange(key, start, stop, **options)
|
603
632
|
end
|
604
633
|
|
605
634
|
# Return a range of members in a sorted set, by index, with scores ordered
|
606
635
|
# from high to low.
|
607
|
-
def zrevrange(key, start, stop, options
|
608
|
-
node_for(key).zrevrange(key, start, stop, options)
|
636
|
+
def zrevrange(key, start, stop, **options)
|
637
|
+
node_for(key).zrevrange(key, start, stop, **options)
|
609
638
|
end
|
610
639
|
|
611
640
|
# Determine the index of a member in a sorted set.
|
@@ -625,14 +654,14 @@ class Redis
|
|
625
654
|
end
|
626
655
|
|
627
656
|
# Return a range of members in a sorted set, by score.
|
628
|
-
def zrangebyscore(key, min, max, options
|
629
|
-
node_for(key).zrangebyscore(key, min, max, options)
|
657
|
+
def zrangebyscore(key, min, max, **options)
|
658
|
+
node_for(key).zrangebyscore(key, min, max, **options)
|
630
659
|
end
|
631
660
|
|
632
661
|
# Return a range of members in a sorted set, by score, with scores ordered
|
633
662
|
# from high to low.
|
634
|
-
def zrevrangebyscore(key, max, min, options
|
635
|
-
node_for(key).zrevrangebyscore(key, max, min, options)
|
663
|
+
def zrevrangebyscore(key, max, min, **options)
|
664
|
+
node_for(key).zrevrangebyscore(key, max, min, **options)
|
636
665
|
end
|
637
666
|
|
638
667
|
# Remove all members in a sorted set within the given scores.
|
@@ -647,16 +676,16 @@ class Redis
|
|
647
676
|
|
648
677
|
# Intersect multiple sorted sets and store the resulting sorted set in a new
|
649
678
|
# key.
|
650
|
-
def zinterstore(destination, keys, options
|
679
|
+
def zinterstore(destination, keys, **options)
|
651
680
|
ensure_same_node(:zinterstore, [destination] + keys) do |node|
|
652
|
-
node.zinterstore(destination, keys, options)
|
681
|
+
node.zinterstore(destination, keys, **options)
|
653
682
|
end
|
654
683
|
end
|
655
684
|
|
656
685
|
# Add multiple sorted sets and store the resulting sorted set in a new key.
|
657
|
-
def zunionstore(destination, keys, options
|
686
|
+
def zunionstore(destination, keys, **options)
|
658
687
|
ensure_same_node(:zunionstore, [destination] + keys) do |node|
|
659
|
-
node.zunionstore(destination, keys, options)
|
688
|
+
node.zunionstore(destination, keys, **options)
|
660
689
|
end
|
661
690
|
end
|
662
691
|
|
@@ -665,9 +694,9 @@ class Redis
|
|
665
694
|
node_for(key).hlen(key)
|
666
695
|
end
|
667
696
|
|
668
|
-
# Set
|
669
|
-
def hset(key,
|
670
|
-
node_for(key).hset(key,
|
697
|
+
# Set multiple hash fields to multiple values.
|
698
|
+
def hset(key, *attrs)
|
699
|
+
node_for(key).hset(key, *attrs)
|
671
700
|
end
|
672
701
|
|
673
702
|
# Set the value of a hash field, only if the field does not exist.
|
@@ -739,7 +768,7 @@ class Redis
|
|
739
768
|
end
|
740
769
|
|
741
770
|
def subscribed?
|
742
|
-
|
771
|
+
!!@subscribed_node
|
743
772
|
end
|
744
773
|
|
745
774
|
# Listen for messages published to the given channels.
|
@@ -757,7 +786,8 @@ class Redis
|
|
757
786
|
|
758
787
|
# Stop listening for messages posted to the given channels.
|
759
788
|
def unsubscribe(*channels)
|
760
|
-
raise
|
789
|
+
raise "Can't unsubscribe if not subscribed." unless subscribed?
|
790
|
+
|
761
791
|
@subscribed_node.unsubscribe(*channels)
|
762
792
|
end
|
763
793
|
|
@@ -773,13 +803,26 @@ class Redis
|
|
773
803
|
end
|
774
804
|
|
775
805
|
# Watch the given keys to determine execution of the MULTI/EXEC block.
|
776
|
-
def watch(*keys)
|
777
|
-
|
806
|
+
def watch(*keys, &block)
|
807
|
+
ensure_same_node(:watch, keys) do |node|
|
808
|
+
@watch_key = key_tag(keys.first) || keys.first.to_s
|
809
|
+
|
810
|
+
begin
|
811
|
+
node.watch(*keys, &block)
|
812
|
+
rescue StandardError
|
813
|
+
@watch_key = nil
|
814
|
+
raise
|
815
|
+
end
|
816
|
+
end
|
778
817
|
end
|
779
818
|
|
780
819
|
# Forget about all watched keys.
|
781
820
|
def unwatch
|
782
|
-
raise CannotDistribute, :unwatch
|
821
|
+
raise CannotDistribute, :unwatch unless @watch_key
|
822
|
+
|
823
|
+
result = node_for(@watch_key).unwatch
|
824
|
+
@watch_key = nil
|
825
|
+
result
|
783
826
|
end
|
784
827
|
|
785
828
|
def pipelined
|
@@ -787,18 +830,30 @@ class Redis
|
|
787
830
|
end
|
788
831
|
|
789
832
|
# Mark the start of a transaction block.
|
790
|
-
def multi
|
791
|
-
raise CannotDistribute, :multi
|
833
|
+
def multi(&block)
|
834
|
+
raise CannotDistribute, :multi unless @watch_key
|
835
|
+
|
836
|
+
result = node_for(@watch_key).multi(&block)
|
837
|
+
@watch_key = nil if block_given?
|
838
|
+
result
|
792
839
|
end
|
793
840
|
|
794
841
|
# Execute all commands issued after MULTI.
|
795
842
|
def exec
|
796
|
-
raise CannotDistribute, :exec
|
843
|
+
raise CannotDistribute, :exec unless @watch_key
|
844
|
+
|
845
|
+
result = node_for(@watch_key).exec
|
846
|
+
@watch_key = nil
|
847
|
+
result
|
797
848
|
end
|
798
849
|
|
799
850
|
# Discard all commands issued after MULTI.
|
800
851
|
def discard
|
801
|
-
raise CannotDistribute, :discard
|
852
|
+
raise CannotDistribute, :discard unless @watch_key
|
853
|
+
|
854
|
+
result = node_for(@watch_key).discard
|
855
|
+
@watch_key = nil
|
856
|
+
result
|
802
857
|
end
|
803
858
|
|
804
859
|
# Control remote script registry.
|
@@ -857,7 +912,7 @@ class Redis
|
|
857
912
|
self.class.new(@node_configs, @default_options)
|
858
913
|
end
|
859
914
|
|
860
|
-
|
915
|
+
protected
|
861
916
|
|
862
917
|
def on_each_node(command, *args)
|
863
918
|
nodes.map do |node|
|
data/lib/redis/errors.rb
CHANGED
data/lib/redis/hash_ring.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'zlib'
|
2
4
|
|
3
5
|
class Redis
|
4
6
|
class HashRing
|
5
|
-
|
6
7
|
POINTS_PER_SERVER = 160 # this is the default in libmemcached
|
7
8
|
|
8
9
|
attr_reader :ring, :sorted_keys, :replicas, :nodes
|
@@ -10,7 +11,7 @@ class Redis
|
|
10
11
|
# nodes is a list of objects that have a proper to_s representation.
|
11
12
|
# replicas indicates how many virtual points should be used pr. node,
|
12
13
|
# replicas are required to improve the distribution.
|
13
|
-
def initialize(nodes=[], replicas=POINTS_PER_SERVER)
|
14
|
+
def initialize(nodes = [], replicas = POINTS_PER_SERVER)
|
14
15
|
@replicas = replicas
|
15
16
|
@ring = {}
|
16
17
|
@nodes = []
|
@@ -32,11 +33,11 @@ class Redis
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def remove_node(node)
|
35
|
-
@nodes.reject!{|n| n.id == node.id}
|
36
|
+
@nodes.reject! { |n| n.id == node.id }
|
36
37
|
@replicas.times do |i|
|
37
38
|
key = Zlib.crc32("#{node.id}:#{i}")
|
38
39
|
@ring.delete(key)
|
39
|
-
@sorted_keys.reject! {|k| k == key}
|
40
|
+
@sorted_keys.reject! { |k| k == key }
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
@@ -46,27 +47,29 @@ class Redis
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def get_node_pos(key)
|
49
|
-
return [nil,nil] if @ring.
|
50
|
+
return [nil, nil] if @ring.empty?
|
51
|
+
|
50
52
|
crc = Zlib.crc32(key)
|
51
53
|
idx = HashRing.binary_search(@sorted_keys, crc)
|
52
|
-
|
54
|
+
[@ring[@sorted_keys[idx]], idx]
|
53
55
|
end
|
54
56
|
|
55
57
|
def iter_nodes(key)
|
56
|
-
return [nil,nil] if @ring.
|
58
|
+
return [nil, nil] if @ring.empty?
|
59
|
+
|
57
60
|
_, pos = get_node_pos(key)
|
58
61
|
@ring.size.times do |n|
|
59
|
-
yield @ring[@sorted_keys[(pos+n) % @ring.size]]
|
62
|
+
yield @ring[@sorted_keys[(pos + n) % @ring.size]]
|
60
63
|
end
|
61
64
|
end
|
62
65
|
|
63
66
|
# Find the closest index in HashRing with value <= the given value
|
64
|
-
def self.binary_search(ary, value
|
67
|
+
def self.binary_search(ary, value)
|
65
68
|
upper = ary.size - 1
|
66
69
|
lower = 0
|
67
70
|
idx = 0
|
68
71
|
|
69
|
-
while
|
72
|
+
while lower <= upper
|
70
73
|
idx = (lower + upper) / 2
|
71
74
|
comp = ary[idx] <=> value
|
72
75
|
|
@@ -79,10 +82,8 @@ class Redis
|
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
if upper < 0
|
83
|
-
|
84
|
-
end
|
85
|
-
return upper
|
85
|
+
upper = ary.size - 1 if upper < 0
|
86
|
+
upper
|
86
87
|
end
|
87
88
|
end
|
88
89
|
end
|
data/lib/redis/pipeline.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
class Pipeline
|
3
5
|
attr_accessor :db
|
@@ -60,7 +62,7 @@ class Redis
|
|
60
62
|
@futures.map(&:timeout)
|
61
63
|
end
|
62
64
|
|
63
|
-
def with_reconnect(val=true)
|
65
|
+
def with_reconnect(val = true)
|
64
66
|
@with_reconnect = false unless val
|
65
67
|
yield
|
66
68
|
end
|
@@ -92,7 +94,8 @@ class Redis
|
|
92
94
|
|
93
95
|
if exec.size < futures.size
|
94
96
|
# Some command wasn't recognized by Redis.
|
95
|
-
|
97
|
+
command_error = replies.detect { |r| r.is_a?(CommandError) }
|
98
|
+
raise command_error
|
96
99
|
end
|
97
100
|
|
98
101
|
super(exec) do |reply|
|
@@ -139,6 +142,16 @@ class Redis
|
|
139
142
|
@object = FutureNotReady
|
140
143
|
end
|
141
144
|
|
145
|
+
def ==(_other)
|
146
|
+
message = +"The methods == and != are deprecated for Redis::Future and will be removed in 4.2.0"
|
147
|
+
message << " - You probably meant to call .value == or .value !="
|
148
|
+
message << " (#{::Kernel.caller(1, 1).first})\n"
|
149
|
+
|
150
|
+
::Kernel.warn(message)
|
151
|
+
|
152
|
+
super
|
153
|
+
end
|
154
|
+
|
142
155
|
def inspect
|
143
156
|
"<Redis::Future #{@command.inspect}>"
|
144
157
|
end
|
@@ -153,7 +166,7 @@ class Redis
|
|
153
166
|
end
|
154
167
|
|
155
168
|
def value
|
156
|
-
::Kernel.raise(@object) if @object.
|
169
|
+
::Kernel.raise(@object) if @object.is_a?(::RuntimeError)
|
157
170
|
@object
|
158
171
|
end
|
159
172
|
|
data/lib/redis/subscribe.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Redis
|
2
4
|
class SubscribedClient
|
3
5
|
def initialize(client)
|
@@ -32,24 +34,21 @@ class Redis
|
|
32
34
|
call([:punsubscribe, *channels])
|
33
35
|
end
|
34
36
|
|
35
|
-
|
37
|
+
protected
|
36
38
|
|
37
39
|
def subscription(start, stop, channels, block, timeout = 0)
|
38
40
|
sub = Subscription.new(&block)
|
39
41
|
|
40
42
|
unsubscribed = false
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
break if unsubscribed
|
48
|
-
end
|
49
|
-
ensure
|
50
|
-
# No need to unsubscribe here. The real client closes the connection
|
51
|
-
# whenever an exception is raised (see #ensure_connected).
|
44
|
+
@client.call_loop([start, *channels], timeout) do |line|
|
45
|
+
type, *rest = line
|
46
|
+
sub.callbacks[type].call(*rest)
|
47
|
+
unsubscribed = type == stop && rest.last == 0
|
48
|
+
break if unsubscribed
|
52
49
|
end
|
50
|
+
# No need to unsubscribe here. The real client closes the connection
|
51
|
+
# whenever an exception is raised (see #ensure_connected).
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
@@ -58,7 +57,7 @@ class Redis
|
|
58
57
|
|
59
58
|
def initialize
|
60
59
|
@callbacks = Hash.new do |hash, key|
|
61
|
-
hash[key] =
|
60
|
+
hash[key] = ->(*_) {}
|
62
61
|
end
|
63
62
|
|
64
63
|
yield(self)
|
data/lib/redis/version.rb
CHANGED