replica_pools 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0f5c202965abf750f17e9d72c0b46e18b0fc4eee
4
- data.tar.gz: 912c2ff07bc4903903b64075e1a47341a58381ed
3
+ metadata.gz: ccf84c0499a86c7e36948d178c8fb150fc71003b
4
+ data.tar.gz: 93bc95a40cd6a411ea255bc3fc94e2e8860add71
5
5
  SHA512:
6
- metadata.gz: e6741659d20dfef95958423f7fd52c7368072a3181daa98526b36e5a00868cd793064c53540e6182faa3c048e6ef5697afa45757c411067ece9b8139d3a00679
7
- data.tar.gz: 11c4329fad66878b81ac76cac6b3a2dc729d90d35a4665dc2167ba3d31fecdc595ea5385e15209e71d1a9b8c9f2b0975c2ac57fc64ba3004b95a951dd47c899c
6
+ metadata.gz: 947621a358c1034cc8a45b70e1f56d1a58126552c700ec18f3e636cfbd80f44eeb9c3288ad3cc78f142a52a3a9df7668cc746f14ba71cd242596998d96bd3182
7
+ data.tar.gz: 4cc0aab455a96d11d2c56fb17e3af40ec8ae33502bf1a70064c71c9e26a043f41ea7ab47937923735408827bb358cb766d5e8dadedeefe57b1206df8ba44e302
data/README.md CHANGED
@@ -160,24 +160,37 @@ Here's one way to accomplish that:
160
160
  end
161
161
  end
162
162
 
163
+ ## Disabling Leader
164
+
165
+ To disable queries to the leader database -- for instance, in a production
166
+ console -- set the disable_leader configuration to false. This will raise
167
+ a ReplicaPools::LeaderDisabled error:
168
+
169
+ ReplicaPools.config.disable_leader = false
170
+
163
171
  ## Running specs
164
172
 
165
- If you haven't already, install the rspec gem, then set up your database
166
- with a test database and a read_only user.
173
+ Tests are run against MySQL 5.6 using docker-compose. 🐋
167
174
 
168
- To match spec/config/database.yml, you can run:
175
+ To get set up, first run:
169
176
 
170
- rake bootstrap
177
+ ```bash
178
+ $ docker-compose up
179
+ $ bundle install
180
+ $ bundle exec rake bootstrap
181
+ ```
171
182
 
172
- From the plugin directory, run:
183
+ Then you can run tests with:
173
184
 
174
- rspec spec
185
+ ```bash
186
+ $ bundle exec rake spec
187
+ ```
175
188
 
176
189
  ## Authors
177
190
 
178
191
  Author: Dan Drabik, Lance Ivy
179
192
 
180
- Copyright (c) 2012-2013, Kickstarter
193
+ Copyright (c) 2012-2018, Kickstarter
181
194
 
182
195
  Released under the MIT license
183
196
 
data/lib/replica_pools.rb CHANGED
@@ -11,6 +11,12 @@ require 'replica_pools/engine' if defined? Rails
11
11
  ActiveRecord::Base.send :include, ReplicaPools::ActiveRecordExtensions
12
12
 
13
13
  module ReplicaPools
14
+ class LeaderDisabled < StandardError
15
+ def to_s
16
+ "Leader database has been disabled. Re-enable with ReplicaPools.config.disable_leader = false."
17
+ end
18
+ end
19
+
14
20
  class << self
15
21
 
16
22
  def config
@@ -45,6 +51,7 @@ module ReplicaPools
45
51
  end
46
52
 
47
53
  def with_leader
54
+ raise LeaderDisabled.new if ReplicaPools.config.disable_leader
48
55
  proxy.with_leader{ yield }
49
56
  end
50
57
 
@@ -5,7 +5,11 @@ module ReplicaPools
5
5
  end
6
6
 
7
7
  def reload(options = nil)
8
- self.class.connection_proxy.with_leader { super }
8
+ if ReplicaPools.config.disable_leader
9
+ super
10
+ else
11
+ self.class.connection_proxy.with_leader { super }
12
+ end
9
13
  end
10
14
 
11
15
  module ClassMethods
@@ -9,6 +9,10 @@ module ReplicaPools
9
9
  # Defaults to false.
10
10
  attr_accessor :defaults_to_leader
11
11
 
12
+ # When true, the leader database will not be selectable.
13
+ # Defaults to false.
14
+ attr_accessor :disable_leader
15
+
12
16
  # The list of methods considered safe to send to a readonly connection.
13
17
  # Defaults are based on Rails version.
14
18
  attr_accessor :safe_methods
@@ -16,6 +20,7 @@ module ReplicaPools
16
20
  def initialize
17
21
  @environment = 'development'
18
22
  @defaults_to_leader = false
23
+ @disable_leader = false
19
24
  @safe_methods = []
20
25
  end
21
26
  end
@@ -55,13 +55,17 @@ module ReplicaPools
55
55
  end
56
56
 
57
57
  def with_leader
58
+ raise LeaderDisabled.new if ReplicaPools.config.disable_leader
59
+
58
60
  last_conn = self.current
59
61
  self.current = leader
60
62
  self.leader_depth += 1
61
63
  yield
62
64
  ensure
63
- self.leader_depth = [leader_depth - 1, 0].max
64
- self.current = last_conn
65
+ if last_conn
66
+ self.leader_depth = [leader_depth - 1, 0].max
67
+ self.current = last_conn
68
+ end
65
69
  end
66
70
 
67
71
  def transaction(*args, &block)
@@ -104,6 +108,7 @@ module ReplicaPools
104
108
  end
105
109
 
106
110
  def route_to(conn, method, *args, &block)
111
+ raise ReplicaPools::LeaderDisabled.new if ReplicaPools.config.disable_leader && conn == leader
107
112
  conn.retrieve_connection.send(method, *args, &block)
108
113
  rescue => e
109
114
  ReplicaPools.log :error, "Error during ##{method}: #{e}"
@@ -117,7 +122,7 @@ module ReplicaPools
117
122
  ReplicaPools.log :error, "Current Connection: #{current}"
118
123
  ReplicaPools.log :error, "Current Pool Name: #{current_pool.name}"
119
124
  ReplicaPools.log :error, "Current Pool Members: #{current_pool.replicas}"
120
- ReplicaPools.log :error, "leader Depth: #{leader_depth}"
125
+ ReplicaPools.log :error, "Leader Depth: #{leader_depth}"
121
126
  end
122
127
  end
123
128
  end
@@ -25,7 +25,11 @@ module ReplicaPools
25
25
  [
26
26
  :select_all, :select_one, :select_value, :select_values,
27
27
  :select_rows, :select, :select_prepared, :verify!, :raw_connection,
28
- :active?, :reconnect!, :disconnect!, :reset_runtime, :log
28
+ :active?, :reconnect!, :disconnect!, :reset_runtime, :log,
29
+ :lookup_cast_type_from_column, :sanitize_limit,
30
+ :combine_bind_parameters, :quote_table_name, :quote, :quote_column_names, :quote_table_names,
31
+ :case_sensitive_comparison, :case_insensitive_comparison,
32
+ :schema_cache, :cacheable_query, :prepared_statements, :clear_cache!
29
33
  ]
30
34
  else
31
35
  warn "Unsupported ActiveRecord version #{ActiveRecord.version}. Please whitelist the safe methods."
@@ -1,3 +1,3 @@
1
1
  module ReplicaPools
2
- VERSION = "2.1.0"
2
+ VERSION = "2.1.1"
3
3
  end
@@ -54,6 +54,19 @@ describe ReplicaPools do
54
54
  end
55
55
  @proxy.send(:within_leader_block?).should_not be
56
56
  end
57
+
58
+ context "with leader_disabled=true" do
59
+ before { ReplicaPools.config.disable_leader = true }
60
+ after { ReplicaPools.config.disable_leader = false }
61
+
62
+ it 'should not execute query, and maintain replica connection' do
63
+ @executed = false
64
+ @proxy.current = @proxy.current_replica
65
+ expect { @proxy.with_leader { @executed = true } }.to raise_error(ReplicaPools::LeaderDisabled)
66
+ @executed.should eq(false)
67
+ @proxy.current.name.should eq('ReplicaPools::DefaultDb1')
68
+ end
69
+ end
57
70
  end
58
71
 
59
72
  context "transaction" do
@@ -124,6 +137,18 @@ describe ReplicaPools do
124
137
  end
125
138
  end
126
139
 
140
+ context "with leader_disabled=true" do
141
+ before { ReplicaPools.config.disable_leader = true }
142
+ after { ReplicaPools.config.disable_leader = false }
143
+ it 'should raise an error instead of sending dangerous methods to the leader' do
144
+ meths = [:insert, :update, :delete, :execute]
145
+ meths.each do |meth|
146
+ @default_replica1.stub(meth).and_raise(RuntimeError)
147
+ expect { @proxy.send(meth, @sql) }.to raise_error(ReplicaPools::LeaderDisabled)
148
+ end
149
+ end
150
+ end
151
+
127
152
  it "should not allow leader depth to get below 0" do
128
153
  @proxy.instance_variable_set("@leader_depth", -500)
129
154
  @proxy.instance_variable_get("@leader_depth").should == -500
@@ -132,7 +157,9 @@ describe ReplicaPools do
132
157
  end
133
158
 
134
159
  it 'should pre-generate safe methods' do
135
- @proxy.should respond_to(:select_value)
160
+ ReplicaPools.config.safe_methods.each do |m|
161
+ @proxy.should respond_to(m)
162
+ end
136
163
  end
137
164
 
138
165
  it 'should dynamically generate unsafe methods' do
@@ -158,6 +185,20 @@ describe ReplicaPools do
158
185
  foo.reload
159
186
  end
160
187
 
188
+ context "with leader_disabled=true" do
189
+ after { ReplicaPools.config.disable_leader = false }
190
+
191
+ it 'should reload models from a replica' do
192
+ foo = TestModel.create!
193
+ ReplicaPools.config.disable_leader = true
194
+ foo = TestModel.last
195
+ @leader.should_not_receive(:select_all)
196
+ @default_replica1.should_receive(:select_all).and_return(ActiveRecord::Result.new(["id"], ["1"]))
197
+ @default_replica2.should_not_receive(:select_all)
198
+ foo.reload
199
+ end
200
+ end
201
+
161
202
  context "with_pool" do
162
203
 
163
204
  it "should switch to the named pool" do
@@ -22,6 +22,16 @@ describe ReplicaPools do
22
22
  ReplicaPools.with_leader
23
23
  end
24
24
 
25
+ describe 'with leader disabled' do
26
+ before { ReplicaPools.config.disable_leader = true }
27
+ after { ReplicaPools.config.disable_leader = false }
28
+
29
+ it 'should delegate with_leader call to connection proxy' do
30
+ @proxy.should_receive(:with_leader).exactly(0)
31
+ expect { ReplicaPools.with_leader }.to raise_error(ReplicaPools::LeaderDisabled)
32
+ end
33
+ end
34
+
25
35
  it 'should delegate current call to connection proxy' do
26
36
  @proxy.should_receive(:current).exactly(1)
27
37
  ReplicaPools.current
data/spec/spec_helper.rb CHANGED
@@ -11,8 +11,7 @@ end
11
11
  require 'active_record'
12
12
  spec_dir = File.dirname(__FILE__)
13
13
  ActiveRecord::Base.logger = Logger.new(spec_dir + "/debug.log")
14
- ActiveRecord::Base.configurations = YAML::load(File.open(spec_dir + '/config/database.yml'))
15
-
14
+ ActiveRecord::Base.configurations = YAML::load(ERB.new(File.read(spec_dir + '/config/database.yml')).result)
16
15
  ActiveRecord::Base.establish_connection :test
17
16
  ActiveRecord::Migration.verbose = false
18
17
  ActiveRecord::Migration.create_table(:test_models, :force => true) {}
@@ -41,4 +40,12 @@ end
41
40
 
42
41
  RSpec.configure do |c|
43
42
  c.include ReplicaPools::Testing
43
+
44
+ # This gem mostly uses the old deprecated shoulda syntax. Support both versions for now.
45
+ c.expect_with :rspec do |c|
46
+ c.syntax = [:expect, :should]
47
+ end
48
+ c.mock_with :rspec do |c|
49
+ c.syntax = [:expect, :should]
50
+ end
44
51
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: replica_pools
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Drabik
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-10-17 00:00:00.000000000 Z
12
+ date: 2018-12-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: 0.3.11
34
+ version: 0.4.4
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: 0.3.11
41
+ version: 0.4.4
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rack
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -139,14 +139,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
139
  version: '1.2'
140
140
  requirements: []
141
141
  rubyforge_project:
142
- rubygems_version: 2.4.5.2
142
+ rubygems_version: 2.4.5.1
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Connection proxy for ActiveRecord for leader / replica setups.
146
146
  test_files:
147
- - spec/config/test_model.rb
148
- - spec/connection_proxy_spec.rb
147
+ - spec/spec_helper.rb
149
148
  - spec/pool_spec.rb
150
- - spec/query_cache_spec.rb
151
149
  - spec/slave_pools_spec.rb
152
- - spec/spec_helper.rb
150
+ - spec/config/test_model.rb
151
+ - spec/query_cache_spec.rb
152
+ - spec/connection_proxy_spec.rb