redis-slave-read 0.1 → 0.2.1
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 +7 -0
- data/Gemfile +1 -0
- data/README.md +1 -1
- data/lib/{activesupport/lib/active_support/cache/redis_slave_read_cache.rb → active_support/cache/redis_store_slave_read.rb} +35 -35
- data/lib/redis-slave-read/version.rb +1 -1
- data/redis-slave-read.gemspec +2 -2
- data/spec/interface/hiredis_spec.rb +23 -18
- metadata +17 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 32c1f6b501f4d1f2e013277b17194a45f555e0cf
|
4
|
+
data.tar.gz: d608989faa6527ac97a0ecc88788928dcecb0509
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e1be26d56b3b8a03279ce70954d5a166c916f3751b8b0d01c247470bf2f4232f32ce2c4a81f70e7dde8619b7c9b56f75e8eda1c3f7c5b02e102e55d582ac1948
|
7
|
+
data.tar.gz: fb782d7638f89f69daa000135a04cb841d3b9049baae79962644bb20fc34249edc7a0e83ca49ef36575c804d77b4328a1f7667b22f3cd04f3d748f2c77c7e465
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Rather than using a Redis instance, create a wrapper that wraps multiple Redis c
|
|
23
23
|
master = Redis.new "localhost:6379"
|
24
24
|
slave1 = Redis.new "localhost:6389"
|
25
25
|
slave2 = Redis.new "localhost:6399"
|
26
|
-
$redis = Redis::SlaveRead::Interface::
|
26
|
+
$redis = Redis::SlaveRead::Interface::Hiredis.new(master: master, slaves: [slave1, slave2])
|
27
27
|
|
28
28
|
Make sure that your slaves are set to be slaved to the master, like `slaveof localhost 6379`
|
29
29
|
|
@@ -1,29 +1,12 @@
|
|
1
|
+
require 'connection_pool'
|
2
|
+
|
1
3
|
module ActiveSupport
|
2
4
|
module Cache
|
3
|
-
class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
# # => host: localhost, port: 6379, db: 0
|
9
|
-
#
|
10
|
-
# RedisStore.new "example.com"
|
11
|
-
# # => host: example.com, port: 6379, db: 0
|
12
|
-
#
|
13
|
-
# RedisStore.new "example.com:23682"
|
14
|
-
# # => host: example.com, port: 23682, db: 0
|
15
|
-
#
|
16
|
-
# RedisStore.new "example.com:23682/1"
|
17
|
-
# # => host: example.com, port: 23682, db: 1
|
18
|
-
#
|
19
|
-
# RedisStore.new "example.com:23682/1/theplaylist"
|
20
|
-
# # => host: example.com, port: 23682, db: 1, namespace: theplaylist
|
21
|
-
#
|
22
|
-
# RedisStore.new "localhost:6379/0", "localhost:6380/0"
|
23
|
-
# # => instantiate a cluster
|
24
|
-
def initialize(*addresses)
|
25
|
-
@data = ::Redis::Factory.create(addresses)
|
26
|
-
super(addresses.extract_options!)
|
5
|
+
class RedisStoreSlaveRead < Store
|
6
|
+
def initialize(options = {})
|
7
|
+
@pool_options = options
|
8
|
+
init_pool @pool_options
|
9
|
+
@options = {}
|
27
10
|
end
|
28
11
|
|
29
12
|
def write(name, value, options = nil)
|
@@ -43,7 +26,7 @@ module ActiveSupport
|
|
43
26
|
instrument(:delete_matched, matcher.inspect) do
|
44
27
|
matcher = key_matcher(matcher, options)
|
45
28
|
begin
|
46
|
-
!(keys =
|
29
|
+
@pool.with {|s| !(keys = s.keys(matcher)).empty? && s.del(*keys) }
|
47
30
|
rescue Errno::ECONNREFUSED => e
|
48
31
|
false
|
49
32
|
end
|
@@ -57,7 +40,7 @@ module ActiveSupport
|
|
57
40
|
# cache.read_multi "rabbit", "white-rabbit"
|
58
41
|
# cache.read_multi "rabbit", "white-rabbit", :raw => true
|
59
42
|
def read_multi(*names)
|
60
|
-
values = @
|
43
|
+
values = @pool.with {|s| s.mget(*names) }
|
61
44
|
|
62
45
|
# Remove the options hash before mapping keys to values
|
63
46
|
names.extract_options!
|
@@ -90,7 +73,7 @@ module ActiveSupport
|
|
90
73
|
# cache.read "rabbit", :raw => true # => "1"
|
91
74
|
def increment(key, amount = 1)
|
92
75
|
instrument(:increment, key, :amount => amount) do
|
93
|
-
@
|
76
|
+
@pool.with {|s| s.incrby key, amount }
|
94
77
|
end
|
95
78
|
end
|
96
79
|
|
@@ -117,36 +100,53 @@ module ActiveSupport
|
|
117
100
|
# cache.read "rabbit", :raw => true # => "-1"
|
118
101
|
def decrement(key, amount = 1)
|
119
102
|
instrument(:decrement, key, :amount => amount) do
|
120
|
-
@
|
103
|
+
@pool.with {|s| s.decrby key, amount }
|
121
104
|
end
|
122
105
|
end
|
123
106
|
|
124
107
|
# Clear all the data from the store.
|
125
108
|
def clear
|
126
109
|
instrument(:clear, nil, nil) do
|
127
|
-
@
|
110
|
+
@pool.with {|s| s.flushdb }
|
128
111
|
end
|
129
112
|
end
|
130
113
|
|
131
114
|
def stats
|
132
|
-
@
|
115
|
+
@pool.with {|s| s.info }
|
133
116
|
end
|
134
117
|
|
135
|
-
# Force client reconnection, useful
|
118
|
+
# Force client reconnection, useful for apps deployed on forking servers.
|
136
119
|
def reconnect
|
137
|
-
@
|
120
|
+
init_pool @pool_options
|
121
|
+
end
|
122
|
+
|
123
|
+
def expire(key, expiry)
|
124
|
+
@pool.with {|s| s.expire key, expiry }
|
138
125
|
end
|
139
126
|
|
140
127
|
protected
|
128
|
+
|
129
|
+
def init_pool(options)
|
130
|
+
interface = options.fetch(:interface, ::Redis::SlaveRead::Interface::Hiredis)
|
131
|
+
@pool.shutdown {|node| node.disconnect } if @pool
|
132
|
+
@pool = ConnectionPool.new(:size => options.fetch(:pool_size, 1), :timeout => options.fetch(:pool_timeout, 3)) do
|
133
|
+
interface.new(
|
134
|
+
master: ::Redis::Store::Factory.create(options[:master]),
|
135
|
+
slaves: options[:slaves].map {|s| ::Redis::Store::Factory.create(s) },
|
136
|
+
read_master: false
|
137
|
+
)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
141
|
def write_entry(key, entry, options)
|
142
142
|
method = options && options[:unless_exist] ? :setnx : :set
|
143
|
-
@
|
143
|
+
@pool.with {|s| s.send method, key, entry, options }
|
144
144
|
rescue Errno::ECONNREFUSED => e
|
145
145
|
false
|
146
146
|
end
|
147
147
|
|
148
148
|
def read_entry(key, options)
|
149
|
-
entry = @
|
149
|
+
entry = @pool.with {|s| s.get key, options }
|
150
150
|
if entry
|
151
151
|
entry.is_a?(ActiveSupport::Cache::Entry) ? entry : ActiveSupport::Cache::Entry.new(entry)
|
152
152
|
end
|
@@ -160,7 +160,7 @@ module ActiveSupport
|
|
160
160
|
# It's really needed and use
|
161
161
|
#
|
162
162
|
def delete_entry(key, options)
|
163
|
-
@
|
163
|
+
@pool.with {|s| s.del key }
|
164
164
|
rescue Errno::ECONNREFUSED => e
|
165
165
|
false
|
166
166
|
end
|
data/redis-slave-read.gemspec
CHANGED
@@ -17,6 +17,6 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.
|
21
|
-
gem.
|
20
|
+
gem.add_runtime_dependency 'redis', '>= 0', '>= 0'
|
21
|
+
gem.add_runtime_dependency 'connection_pool'
|
22
22
|
end
|
@@ -7,15 +7,15 @@ describe Redis::SlaveRead::Interface::Hiredis do
|
|
7
7
|
subject { described_class.new master: master, slaves: slaves }
|
8
8
|
|
9
9
|
it "should distribute reads between all available nodes" do
|
10
|
-
master.
|
11
|
-
slaves[0].
|
12
|
-
slaves[1].
|
10
|
+
expect(master).to receive(:get).once
|
11
|
+
expect(slaves[0]).to receive(:get).once
|
12
|
+
expect(slaves[1]).to receive(:get).once
|
13
13
|
|
14
14
|
3.times { subject.get "foo" }
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should always send non-reads to the master" do
|
18
|
-
master.
|
18
|
+
expect(master).to receive(:set).exactly(3).times
|
19
19
|
|
20
20
|
3.times { subject.set "foo", "bar" }
|
21
21
|
end
|
@@ -24,9 +24,9 @@ describe Redis::SlaveRead::Interface::Hiredis do
|
|
24
24
|
subject { described_class.new master: master, slaves: slaves, read_master: false }
|
25
25
|
|
26
26
|
it "should distribute reads between all available slaves" do
|
27
|
-
master.
|
28
|
-
slaves[1].
|
29
|
-
slaves[0].
|
27
|
+
expect(master).to receive(:get).never
|
28
|
+
expect(slaves[1]).to receive(:get).twice
|
29
|
+
expect(slaves[0]).to receive(:get).once
|
30
30
|
|
31
31
|
3.times { subject.get "foo" }
|
32
32
|
end
|
@@ -34,7 +34,7 @@ describe Redis::SlaveRead::Interface::Hiredis do
|
|
34
34
|
|
35
35
|
context "when in a multi block" do
|
36
36
|
it "sends all commands to the master" do
|
37
|
-
master.
|
37
|
+
expect(master).to receive(:get).twice
|
38
38
|
|
39
39
|
subject.multi do
|
40
40
|
2.times { subject.get "foo" }
|
@@ -44,7 +44,7 @@ describe Redis::SlaveRead::Interface::Hiredis do
|
|
44
44
|
|
45
45
|
context "when in a pipelined block" do
|
46
46
|
it "sends all commands to the master" do
|
47
|
-
master.
|
47
|
+
expect(master).to receive(:get).twice
|
48
48
|
|
49
49
|
subject.pipelined do
|
50
50
|
2.times { subject.get "foo" }
|
@@ -54,23 +54,28 @@ describe Redis::SlaveRead::Interface::Hiredis do
|
|
54
54
|
|
55
55
|
context "commands that distribute to all nodes" do
|
56
56
|
it "should distribute to each node" do
|
57
|
-
master.
|
58
|
-
slaves.each {|slave| slave.
|
57
|
+
expect(master).to receive(:select).once
|
58
|
+
slaves.each {|slave| expect(slave).to receive(:select).once }
|
59
59
|
subject.send(:select)
|
60
60
|
end
|
61
61
|
|
62
62
|
it "should set the DB on each node" do
|
63
63
|
subject.select 4
|
64
|
-
master.client.db.
|
65
|
-
slaves[0].client.db.
|
66
|
-
slaves[1].client.db.
|
64
|
+
expect(master.client.db).to eq 4
|
65
|
+
expect(slaves[0].client.db).to eq 4
|
66
|
+
expect(slaves[1].client.db).to eq 4
|
67
67
|
end
|
68
68
|
|
69
|
-
it "should disconnect each client" do
|
69
|
+
it "should connect and disconnect each client" do
|
70
|
+
subject.connect
|
71
|
+
expect(!!master.client.connected?).to be_truthy
|
72
|
+
expect(!!slaves[0].client.connected?).to be_truthy
|
73
|
+
expect(!!slaves[1].client.connected?).to be_truthy
|
74
|
+
|
70
75
|
subject.disconnect
|
71
|
-
!!master.client.connected
|
72
|
-
!!slaves[0].client.connected
|
73
|
-
!!slaves[1].client.connected
|
76
|
+
expect(!!master.client.connected?).to be_falsey
|
77
|
+
expect(!!slaves[0].client.connected?).to be_falsey
|
78
|
+
expect(!!slaves[1].client.connected?).to be_falsey
|
74
79
|
end
|
75
80
|
end
|
76
81
|
end
|
metadata
CHANGED
@@ -1,48 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis-slave-read
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: '0.1'
|
4
|
+
version: 0.2.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Chris Heald
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-04-27 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
|
14
|
+
name: redis
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
20
|
+
type: :runtime
|
22
21
|
prerelease: false
|
23
22
|
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
23
|
requirements:
|
26
|
-
- -
|
24
|
+
- - ">="
|
27
25
|
- !ruby/object:Gem::Version
|
28
26
|
version: '0'
|
29
|
-
name: redis
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
|
-
|
28
|
+
name: connection_pool
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
34
|
+
type: :runtime
|
38
35
|
prerelease: false
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
none: false
|
41
37
|
requirements:
|
42
|
-
- -
|
38
|
+
- - ">="
|
43
39
|
- !ruby/object:Gem::Version
|
44
40
|
version: '0'
|
45
|
-
name: redis
|
46
41
|
description: Provides load balancing of reads in a cluster of Redis replicas
|
47
42
|
email:
|
48
43
|
- cheald@gmail.com
|
@@ -50,12 +45,12 @@ executables: []
|
|
50
45
|
extensions: []
|
51
46
|
extra_rdoc_files: []
|
52
47
|
files:
|
53
|
-
- .gitignore
|
48
|
+
- ".gitignore"
|
54
49
|
- Gemfile
|
55
50
|
- LICENSE.txt
|
56
51
|
- README.md
|
57
52
|
- Rakefile
|
58
|
-
- lib/
|
53
|
+
- lib/active_support/cache/redis_store_slave_read.rb
|
59
54
|
- lib/redis-slave-read.rb
|
60
55
|
- lib/redis-slave-read/interface/base.rb
|
61
56
|
- lib/redis-slave-read/interface/hiredis.rb
|
@@ -65,29 +60,27 @@ files:
|
|
65
60
|
- spec/spec_helper.rb
|
66
61
|
homepage: ''
|
67
62
|
licenses: []
|
63
|
+
metadata: {}
|
68
64
|
post_install_message:
|
69
65
|
rdoc_options: []
|
70
66
|
require_paths:
|
71
67
|
- lib
|
72
68
|
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
69
|
requirements:
|
75
|
-
- -
|
70
|
+
- - ">="
|
76
71
|
- !ruby/object:Gem::Version
|
77
72
|
version: '0'
|
78
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
-
none: false
|
80
74
|
requirements:
|
81
|
-
- -
|
75
|
+
- - ">="
|
82
76
|
- !ruby/object:Gem::Version
|
83
77
|
version: '0'
|
84
78
|
requirements: []
|
85
79
|
rubyforge_project:
|
86
|
-
rubygems_version:
|
80
|
+
rubygems_version: 2.5.1
|
87
81
|
signing_key:
|
88
|
-
specification_version:
|
82
|
+
specification_version: 4
|
89
83
|
summary: Provides load balancing of reads in a cluster of Redis replicas
|
90
84
|
test_files:
|
91
85
|
- spec/interface/hiredis_spec.rb
|
92
86
|
- spec/spec_helper.rb
|
93
|
-
has_rdoc:
|