replica_pools 2.1.0 → 2.1.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 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