ar-octopus 0.8.4 → 0.8.5

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: 663045a0938adf065becc68b2ed936fdadca804b
4
- data.tar.gz: bd3e9ce12b5c7c33f15c76ee2f138c37953a775a
3
+ metadata.gz: a2e171072013526c5597b2d233d983f129a84cec
4
+ data.tar.gz: 0c05c12e05f5dfb64aaf6f15e0accb59c2174a53
5
5
  SHA512:
6
- metadata.gz: 7da33ad1580e5b30fea1a94182f8ccb7f8ac718547bfb9338336786c146fd04a465ec0231ab93af5f19d76dfe13d5fd62fed745cfbf251ed2793f143f1e17db4
7
- data.tar.gz: 3b6bb393f346d75b9ff859996c625274a16dd7a00bac901c8ff09191f1b12a3a78191d05ba7fab8492f596420bd061a625931ca0c1b120cdf9708cb3ff5fc1d1
6
+ metadata.gz: 19f50eb815a6273a87430354c5124096d90d561a8b27c1bfe0073a5a81f3a2242c71f099b88db0bab031018c56a8662ed587122412a0042ba543bc41c6b0d745
7
+ data.tar.gz: 11828df91744a59445fe6a4add2c6081971f724ed9394b96eb12b36c6a09e69db2546d7dc1eadc56c19074ed5de1d7cd28f39a38c0bd7d3ad88030238a46a98e
@@ -1 +1 @@
1
- 2.1.2
1
+ 2.1.5
@@ -4,14 +4,18 @@ env:
4
4
  before_script:
5
5
  - "bundle exec rake db:prepare"
6
6
  rvm:
7
- - 1.9.3
8
7
  - 2.0.0
9
- - 2.1.1
8
+ - 2.1.5
9
+ - 2.2.0
10
10
  gemfile:
11
- - gemfiles/rails32.gemfile
12
11
  - gemfiles/rails4.gemfile
13
12
  - gemfiles/rails41.gemfile
13
+ - gemfiles/rails42.gemfile
14
14
  notifications:
15
15
  recipients:
16
16
  - gabriel.sobrinho@gmail.com
17
17
  - thiago.pradi@gmail.com
18
+ matrix:
19
+ include:
20
+ - rvm: 1.9.3
21
+ gemfile: gemfiles/rails32.gemfile
data/Appraisals CHANGED
@@ -10,4 +10,7 @@ appraise "rails41" do
10
10
  gem "activerecord", "~> 4.1.0"
11
11
  end
12
12
 
13
+ appraise "rails42" do
14
+ gem "activerecord", "~> 4.2.0"
15
+ end
13
16
  # vim: ft=ruby
@@ -158,6 +158,24 @@ class CustomConnection < ActiveRecord::Base
158
158
  end
159
159
  ```
160
160
 
161
+ ### allow_shard
162
+ If you'd like to use specific shards with a model that has a Rails-managed connection, you can use `allow_shard`:
163
+
164
+ ```ruby
165
+ class CustomConnectedModel
166
+ octopus_establish_connection(...)
167
+ allow_shard :my_shard
168
+ end
169
+
170
+ #This uses :my_shard
171
+ CustomConnectedModel.using(:my_shard).first
172
+
173
+ #This uses the Rails-managed connection pool (the call to 'using' is ignored)
174
+ CustomConnectedModel.using(:some_other_shard).first
175
+ ```
176
+
177
+ This can be useful if you have a model that lives in a separate database and would like to add sharding or replication to it. For other use cases, you may be better off with <a href="https://github.com/tchandy/octopus/wiki/Slave-Groups">slave groups</a>.
178
+
161
179
  ## Contributing with Octopus
162
180
  Contributors are welcome! To run the test suite, you need mysql, postgresql and sqlite3 installed. This is what you need to setup your Octopus development environment:
163
181
 
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'appraisal'
6
6
  RSpec::Core::RakeTask.new
7
7
  RuboCop::RakeTask.new
8
8
 
9
- task :default => [:spec, :rubocop]
9
+ task :default => [:spec]
10
10
 
11
11
  namespace :db do
12
12
  desc 'Build the databases for tests'
@@ -127,6 +127,7 @@ namespace :db do
127
127
  u.string :name
128
128
  u.string :commentable_type
129
129
  u.integer :commentable_id
130
+ u.boolean :open, default: false
130
131
  end
131
132
 
132
133
  BlankModel.using(shard_symbol).connection.create_table(:parts) do |u|
@@ -142,6 +143,10 @@ namespace :db do
142
143
  u.string :name
143
144
  end
144
145
 
146
+ BlankModel.using(shard_symbol).connection.create_table(:custom) do |u|
147
+ u.string :value
148
+ end
149
+
145
150
  if shard_symbol == :alone_shard
146
151
  BlankModel.using(shard_symbol).connection.create_table(:mmorpg_players) do |u|
147
152
  u.string :player_name
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 4.2.0"
6
+
7
+ gemspec :path => "../"
@@ -64,6 +64,20 @@ module Octopus
64
64
  @environments ||= config['environments'] || ['production']
65
65
  end
66
66
 
67
+ def self.robust_environments=(environments)
68
+ @robust_environments = environments.map(&:to_s)
69
+ end
70
+
71
+ # Environments in which to swallow failures from a single shard
72
+ # when iterating through all.
73
+ def self.robust_environments
74
+ @robust_environments ||= config['robust_environments'] || ['production']
75
+ end
76
+
77
+ def self.robust_environment?
78
+ robust_environments.include? rails_env
79
+ end
80
+
67
81
  def self.rails3?
68
82
  ActiveRecord::VERSION::MAJOR <= 3
69
83
  end
@@ -80,6 +94,16 @@ module Octopus
80
94
  defined?(Rails)
81
95
  end
82
96
 
97
+ attr_writer :logger
98
+
99
+ def self.logger
100
+ if defined?(Rails)
101
+ @logger ||= Rails.logger
102
+ else
103
+ @logger ||= Logger.new($stderr)
104
+ end
105
+ end
106
+
83
107
  def self.shards=(shards)
84
108
  config[rails_env] = HashWithIndifferentAccess.new(shards)
85
109
  ActiveRecord::Base.connection.initialize_shards(@config)
@@ -44,10 +44,12 @@ module Octopus
44
44
  return unless Octopus.enabled?
45
45
 
46
46
  if new_record? || self.class.connection_proxy.block
47
- self.current_shard = self.class.connection_proxy.current_shard
47
+ shard = self.class.connection_proxy.current_shard
48
48
  else
49
- self.current_shard = self.class.connection_proxy.last_current_shard || self.class.connection_proxy.current_shard
49
+ shard = self.class.connection_proxy.last_current_shard || self.class.connection_proxy.current_shard
50
50
  end
51
+
52
+ self.current_shard = shard if self.class.allowed_shard?(shard)
51
53
  end
52
54
 
53
55
  def should_set_current_shard?
@@ -75,6 +77,7 @@ module Octopus
75
77
  def self.extended(base)
76
78
  base.class_attribute(:replicated)
77
79
  base.class_attribute(:sharded)
80
+ base.class_attribute(:allowed_shards)
78
81
  base.hijack_methods
79
82
  end
80
83
 
@@ -86,8 +89,13 @@ module Octopus
86
89
  self.sharded = true
87
90
  end
88
91
 
92
+ def allow_shard(*shards)
93
+ self.allowed_shards ||= []
94
+ self.allowed_shards += shards
95
+ end
96
+
89
97
  def hijack_methods
90
- around_save :run_on_shard
98
+ around_save :run_on_shard, :unless => -> { self.class.custom_octopus_connection }
91
99
  after_initialize :set_current_shard
92
100
 
93
101
  class << self
@@ -116,7 +124,19 @@ module Octopus
116
124
  end
117
125
 
118
126
  def should_use_normal_connection?
119
- !Octopus.enabled? || custom_octopus_connection
127
+ if !Octopus.enabled?
128
+ true
129
+ elsif custom_octopus_connection
130
+ !connection_proxy.block || !allowed_shard?(connection_proxy.current_shard)
131
+ end
132
+ end
133
+
134
+ def allowed_shard?(shard)
135
+ if custom_octopus_connection
136
+ allowed_shards && shard && allowed_shards.include?(shard)
137
+ else
138
+ true
139
+ end
120
140
  end
121
141
 
122
142
  def connection_with_octopus
@@ -25,7 +25,7 @@ module Octopus
25
25
  run_on_shard { super }
26
26
  end
27
27
 
28
- def touch(name = nil)
28
+ def touch(*args)
29
29
  run_on_shard { super }
30
30
  end
31
31
 
@@ -17,7 +17,7 @@ module Octopus
17
17
  @slave_groups = HashWithIndifferentAccess.new
18
18
  @groups = {}
19
19
  @adapters = Set.new
20
- @config = ActiveRecord::Base.connection_pool_without_octopus.connection.instance_variable_get(:@config)
20
+ @config = ActiveRecord::Base.connection_pool_without_octopus.spec.config
21
21
 
22
22
  unless config.nil?
23
23
  @entire_sharded = config['entire_sharded']
@@ -202,6 +202,9 @@ module Octopus
202
202
  # reconnect, but in Rails 3.1 the flag prevents this.
203
203
  def safe_connection(connection_pool)
204
204
  connection_pool.automatic_reconnect ||= true
205
+ if !connection_pool.connected? && @shards[:master].connection.query_cache_enabled
206
+ connection_pool.connection.enable_query_cache!
207
+ end
205
208
  connection_pool.connection
206
209
  end
207
210
 
@@ -218,7 +221,7 @@ module Octopus
218
221
  end
219
222
 
220
223
  def run_queries_on_shard(shard, &_block)
221
- keeping_connection_proxy do
224
+ keeping_connection_proxy(shard) do
222
225
  using_shard(shard) do
223
226
  yield
224
227
  end
@@ -233,8 +236,9 @@ module Octopus
233
236
 
234
237
  def clean_connection_proxy
235
238
  self.current_shard = :master
239
+ self.current_model = nil
236
240
  self.current_group = nil
237
- self.block = false
241
+ self.block = nil
238
242
  end
239
243
 
240
244
  def check_schema_migrations(shard)
@@ -244,8 +248,7 @@ module Octopus
244
248
  end
245
249
 
246
250
  def transaction(options = {}, &block)
247
- replicated = @replicated && (current_model.replicated || fully_replicated?)
248
- if !sharded && replicated
251
+ if !sharded && current_model_replicated?
249
252
  run_queries_on_shard(:master) do
250
253
  select_connection.transaction(options, &block)
251
254
  end
@@ -281,23 +284,23 @@ module Octopus
281
284
 
282
285
  def enable_query_cache!
283
286
  clear_query_cache
284
- @shards.each { |_k, v| safe_connection(v).enable_query_cache! }
287
+ with_each_healthy_shard { |v| v.connected? && safe_connection(v).enable_query_cache! }
285
288
  end
286
289
 
287
290
  def disable_query_cache!
288
- @shards.each { |_k, v| safe_connection(v).disable_query_cache! }
291
+ with_each_healthy_shard { |v| v.connected? && safe_connection(v).disable_query_cache! }
289
292
  end
290
293
 
291
294
  def clear_query_cache
292
- @shards.each { |_k, v| safe_connection(v).clear_query_cache }
295
+ with_each_healthy_shard { |v| v.connected? && safe_connection(v).clear_query_cache }
293
296
  end
294
297
 
295
298
  def clear_active_connections!
296
- @shards.each { |_k, v| v.release_connection }
299
+ with_each_healthy_shard(&:release_connection)
297
300
  end
298
301
 
299
302
  def clear_all_connections!
300
- @shards.each { |_k, v| v.disconnect! }
303
+ with_each_healthy_shard(&:disconnect!)
301
304
  end
302
305
 
303
306
  def connected?
@@ -322,6 +325,44 @@ module Octopus
322
325
 
323
326
  protected
324
327
 
328
+ # Ensure that a single failing slave doesn't take down the entire application
329
+ def with_each_healthy_shard
330
+ @shards.each do |shard_name, v|
331
+ begin
332
+ yield(v)
333
+ rescue => e
334
+ if Octopus.robust_environment?
335
+ Octopus.logger.error "Error on shard #{shard_name}: #{e.message}"
336
+ else
337
+ raise
338
+ end
339
+ end
340
+ end
341
+
342
+ conn_handler = ActiveRecord::Base.connection_handler
343
+ if conn_handler.respond_to?(:connection_pool_list)
344
+ # Rails 4+
345
+ ar_pools = conn_handler.connection_pool_list
346
+ else
347
+ # Rails 3.2
348
+ ar_pools = conn_handler.connection_pools.values
349
+ end
350
+
351
+ ar_pools.each do |pool|
352
+ next if pool == @shards[:master] # Already handled this
353
+
354
+ begin
355
+ yield(pool)
356
+ rescue => e
357
+ if Octopus.robust_environment?
358
+ Octopus.logger.error "Error on pool (spec: #{pool.spec}): #{e.message}"
359
+ else
360
+ raise
361
+ end
362
+ end
363
+ end
364
+ end
365
+
325
366
  def connection_pool_for(adapter, config)
326
367
  if Octopus.rails4?
327
368
  arg = ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(adapter.dup, config)
@@ -356,7 +397,7 @@ module Octopus
356
397
  end
357
398
 
358
399
  def should_clean_connection_proxy?(method)
359
- method.to_s =~ /insert|select|execute/ && !@replicated && !block
400
+ method.to_s =~ /insert|select|execute/ && !current_model_replicated? && (!block || block != current_shard)
360
401
  end
361
402
 
362
403
  # Try to use slaves if and only if `replicated: true` is specified in `shards.yml` and no slaves groups are defined
@@ -364,6 +405,10 @@ module Octopus
364
405
  @replicated && method.to_s =~ /select/ && !block && !slaves_grouped?
365
406
  end
366
407
 
408
+ def current_model_replicated?
409
+ @replicated && (current_model.try(:replicated) || fully_replicated?)
410
+ end
411
+
367
412
  def send_queries_to_selected_slave(method, *args, &block)
368
413
  if current_model.replicated || fully_replicated?
369
414
  selected_slave = @slaves_load_balancer.next
@@ -384,7 +429,7 @@ module Octopus
384
429
  # while ensuring that we revert `current_shard` from the selected slave to the (shard's) master
385
430
  # not to make queries other than SELECT leak to the slave.
386
431
  def should_use_slaves_for_method?(method)
387
- @replicated && (current_model.replicated || fully_replicated?) && method.to_s =~ /select/
432
+ current_model_replicated? && method.to_s =~ /select/
388
433
  end
389
434
 
390
435
  def slaves_grouped?
@@ -409,14 +454,14 @@ module Octopus
409
454
  #
410
455
  # @see Octopus::Proxy#should_clean_connection?
411
456
  # @see Octopus::Proxy#clean_connection_proxy
412
- def keeping_connection_proxy(&_block)
457
+ def keeping_connection_proxy(shard, &_block)
413
458
  last_block = block
414
459
 
415
460
  begin
416
- self.block = true
461
+ self.block = shard
417
462
  yield
418
463
  ensure
419
- self.block = last_block || false
464
+ self.block = last_block || nil
420
465
  end
421
466
  end
422
467
 
@@ -425,7 +470,9 @@ module Octopus
425
470
  older_shard = current_shard
426
471
 
427
472
  begin
428
- self.current_shard = shard
473
+ unless current_model && !current_model.allowed_shard?(shard)
474
+ self.current_shard = shard
475
+ end
429
476
  yield
430
477
  ensure
431
478
  self.current_shard = older_shard
@@ -17,7 +17,7 @@ module Octopus
17
17
  end
18
18
 
19
19
  def method_missing(method, *args, &block)
20
- run_on_shard { @ar_relation.send(method, *args, &block) }
20
+ run_on_shard { @ar_relation.public_send(method, *args, &block) }
21
21
  end
22
22
 
23
23
  def ==(other)
@@ -28,13 +28,19 @@ module Octopus
28
28
  end
29
29
 
30
30
  def connection
31
- @klass.connection.current_shard = @current_shard
32
- @klass.connection
31
+ @klass.connection_proxy.current_shard = @current_shard
32
+
33
+ if @klass.custom_octopus_connection && @klass.allowed_shard?(@current_shard)
34
+ # Force use of proxy, given we called 'using' explicitly to get here
35
+ @klass.connection_proxy.current_model = @klass
36
+ @klass.connection_proxy
37
+ else
38
+ @klass.connection
39
+ end
33
40
  end
34
41
 
35
42
  def method_missing(method, *args, &block)
36
43
  result = run_on_shard { @klass.send(method, *args, &block) }
37
-
38
44
  if result.respond_to?(:all)
39
45
  @klass = result
40
46
  return self
@@ -1,3 +1,3 @@
1
1
  module Octopus
2
- VERSION = '0.8.4'
2
+ VERSION = '0.8.5'
3
3
  end
@@ -3,6 +3,12 @@ mysql: &mysql
3
3
  username: <%= ENV['MYSQL_USER'] || 'root' %>
4
4
  host: localhost
5
5
 
6
+ mysql_unavailable: &mysql_unavailable
7
+ adapter: mysql2
8
+ username: <%= ENV['MYSQL_USER'] || 'root' %>
9
+ host: 192.0.2.1
10
+ connect_timeout: 3
11
+
6
12
  octopus: &octopus
7
13
  shards:
8
14
  alone_shard:
@@ -87,6 +93,13 @@ replicated_with_one_slave:
87
93
  database: octopus_shard_2
88
94
  <<: *mysql
89
95
 
96
+ replicated_with_one_slave_unavailable:
97
+ replicated: true
98
+ shards:
99
+ slave1:
100
+ database: octopus_shard_2
101
+ <<: *mysql_unavailable
102
+
90
103
 
91
104
  production_fully_replicated:
92
105
  replicated: true
@@ -91,7 +91,7 @@ describe Octopus::Model do
91
91
 
92
92
  it 'should work when you have a SQLite3 shard' do
93
93
  u = User.using(:sqlite_shard).create!(:name => 'Sqlite3')
94
- expect(User.using(:sqlite_shard).find_by_name('Sqlite3')).to eq(u)
94
+ expect(User.using(:sqlite_shard).where(name: 'Sqlite3').first).to eq(u)
95
95
  end
96
96
 
97
97
  it 'should clean #current_shard from proxy when using execute' do
@@ -471,6 +471,99 @@ describe Octopus::Model do
471
471
  end
472
472
  end
473
473
 
474
+ describe 'custom connection' do
475
+ context 'by default' do
476
+ it 'with plain call should use custom connection' do
477
+ expect(CustomConnection.connection.current_database).to eq('octopus_shard_2')
478
+ end
479
+
480
+ it 'should ignore using called on relation' do
481
+ expect(CustomConnection.using(:postgresql_shard).connection.current_database).to eq('octopus_shard_2')
482
+ end
483
+
484
+ it 'should ignore Octopus.using block' do
485
+ Octopus.using(:postgresql_shard) do
486
+ expect(CustomConnection.connection.current_database).to eq('octopus_shard_2')
487
+ end
488
+ end
489
+
490
+ it 'should save to correct shard' do
491
+ expect { CustomConnection.create(:value => 'custom value') }.to change {
492
+ CustomConnection
493
+ .connection
494
+ .execute("select count(*) as ct from custom where value = 'custom value'")
495
+ .to_a.first.first
496
+ }.by 1
497
+ end
498
+ end
499
+
500
+ context 'with allowed_shards configured' do
501
+ before do
502
+ CustomConnection.allow_shard :postgresql_shard
503
+ end
504
+
505
+ it 'with plain call should use custom connection' do
506
+ expect(CustomConnection.connection.current_database).to eq('octopus_shard_2')
507
+ end
508
+
509
+ it 'with using called on relation with allowed shard should use' do
510
+ expect(CustomConnection.using(:postgresql_shard).connection.current_database).to eq('octopus_shard_1')
511
+ end
512
+
513
+ it 'within Octopus.using block with allowed shard should use' do
514
+ Octopus.using(:postgresql_shard) do
515
+ expect(CustomConnection.connection.current_database).to eq('octopus_shard_1')
516
+ end
517
+ end
518
+
519
+ it 'with using called on relation with disallowed shard should not use' do
520
+ expect(CustomConnection.using(:brazil).connection.current_database).to eq('octopus_shard_2')
521
+ end
522
+
523
+ it 'within Octopus.using block with disallowed shard should not use' do
524
+ Octopus.using(:brazil) do
525
+ expect(CustomConnection.connection.current_database).to eq('octopus_shard_2')
526
+ end
527
+ end
528
+
529
+ it 'should save to correct shard' do
530
+ expect { CustomConnection.create(:value => 'custom value') }.to change {
531
+ CustomConnection
532
+ .connection
533
+ .execute("select count(*) as ct from custom where value = 'custom value'")
534
+ .to_a.first.first
535
+ }.by 1
536
+ end
537
+
538
+ it 'should clean up correctly' do
539
+ User.create!(:name => 'CleanUser')
540
+ CustomConnection.using(:postgresql_shard).first
541
+ expect(User.first).not_to be_nil
542
+ end
543
+
544
+ it 'should clean up correctly even inside block' do
545
+ User.create!(:name => 'CleanUser')
546
+
547
+ Octopus.using(:master) do
548
+ CustomConnection.using(:postgresql_shard).connection.execute('select count(*) from users')
549
+ expect(User.first).not_to be_nil
550
+ end
551
+ end
552
+ end
553
+
554
+ describe 'clear_active_connections!' do
555
+ it 'should not leak connection' do
556
+ CustomConnection.create(:value => 'custom value')
557
+
558
+ # This is what Rails, Sidekiq etc call--this normally handles all connection pools in the app
559
+ expect { ActiveRecord::Base.clear_active_connections! }
560
+ .to change { CustomConnection.connection_pool.active_connection? }
561
+
562
+ expect(CustomConnection.connection_pool.active_connection?).to be_falsey
563
+ end
564
+ end
565
+ end
566
+
474
567
  describe 'when using set_table_name' do
475
568
  it 'should work correctly' do
476
569
  Bacon.using(:brazil).create!(:name => 'YUMMMYYYY')
@@ -12,6 +12,13 @@ describe Octopus::RelationProxy do
12
12
  expect(@relation.current_shard).to eq(:canada)
13
13
  end
14
14
 
15
+ unless Octopus.rails3?
16
+ it 'can define collection association with the same name as ancestor private method' do
17
+ @client.comments << Comment.using(:canada).create!(open: true)
18
+ expect(@client.comments.open).to be_a_kind_of(ActiveRecord::Relation)
19
+ end
20
+ end
21
+
15
22
  context 'when comparing to other Relation objects' do
16
23
  before :each do
17
24
  @relation.reset
@@ -27,23 +27,33 @@ describe 'when the database is replicated' do
27
27
  end
28
28
 
29
29
  describe 'When enabling the query cache' do
30
- include_context 'with query cache enabled'
31
-
32
- it 'should do the queries with cache' do
33
- OctopusHelper.using_environment :replicated_with_one_slave do
34
- cat1 = Cat.using(:master).create!(:name => 'Master Cat 1')
35
- _ct2 = Cat.using(:master).create!(:name => 'Master Cat 2')
36
- expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
37
- expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
38
- expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
39
-
40
- cat3 = Cat.using(:slave1).create!(:name => 'Slave Cat 3')
41
- _ct4 = Cat.using(:slave1).create!(:name => 'Slave Cat 4')
42
- expect(Cat.find(cat3.id).id).to eq(cat3.id)
43
- expect(Cat.find(cat3.id).id).to eq(cat3.id)
44
- expect(Cat.find(cat3.id).id).to eq(cat3.id)
45
-
46
- expect(counter.query_count).to eq(16)
30
+ include_context 'with query cache enabled' do
31
+ it 'should do the queries with cache' do
32
+ OctopusHelper.using_environment :replicated_with_one_slave do
33
+ cat1 = Cat.using(:master).create!(:name => 'Master Cat 1')
34
+ _ct2 = Cat.using(:master).create!(:name => 'Master Cat 2')
35
+ expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
36
+ expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
37
+ expect(Cat.using(:master).find(cat1.id)).to eq(cat1)
38
+
39
+ cat3 = Cat.using(:slave1).create!(:name => 'Slave Cat 3')
40
+ _ct4 = Cat.using(:slave1).create!(:name => 'Slave Cat 4')
41
+ expect(Cat.find(cat3.id).id).to eq(cat3.id)
42
+ expect(Cat.find(cat3.id).id).to eq(cat3.id)
43
+ expect(Cat.find(cat3.id).id).to eq(cat3.id)
44
+
45
+ expect(counter.query_count).to eq(14)
46
+ end
47
+ end
48
+ end
49
+ end
50
+
51
+ describe 'When enabling the query cache with slave unavailable' do
52
+ it "should not raise can't connect error" do
53
+ OctopusHelper.using_environment :replicated_with_one_slave_unavailable do
54
+ expect {
55
+ ActiveRecord::Base.connection.enable_query_cache!
56
+ }.to_not raise_error
47
57
  end
48
58
  end
49
59
  end
@@ -27,6 +27,7 @@ end
27
27
 
28
28
  # This class sets its own connection
29
29
  class CustomConnection < ActiveRecord::Base
30
+ self.table_name = 'custom'
30
31
  octopus_establish_connection(:adapter => 'mysql2', :database => 'octopus_shard_2', :username => 'root', :password => '')
31
32
  end
32
33
 
@@ -75,6 +76,7 @@ end
75
76
 
76
77
  class Comment < ActiveRecord::Base
77
78
  belongs_to :commentable, :polymorphic => true
79
+ scope :open, -> { where(open: true) }
78
80
  end
79
81
 
80
82
  class Bacon < ActiveRecord::Base
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ar-octopus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thiago Pradi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-10-23 00:00:00.000000000 Z
13
+ date: 2015-03-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -178,6 +178,7 @@ files:
178
178
  - gemfiles/rails32.gemfile
179
179
  - gemfiles/rails4.gemfile
180
180
  - gemfiles/rails41.gemfile
181
+ - gemfiles/rails42.gemfile
181
182
  - init.rb
182
183
  - lib/ar-octopus.rb
183
184
  - lib/octopus.rb
@@ -341,7 +342,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
341
342
  version: '0'
342
343
  requirements: []
343
344
  rubyforge_project:
344
- rubygems_version: 2.2.2
345
+ rubygems_version: 2.4.4
345
346
  signing_key:
346
347
  specification_version: 4
347
348
  summary: Easy Database Sharding for ActiveRecord