multi_db 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -137,6 +137,35 @@ And add this to your ApplicationController:
137
137
  *NOTE*: It's not possible to toggle this mode in a running process, as the dynamically
138
138
  generated methods will have the initially defined "stickyness" built in.
139
139
 
140
+ === Using the weighted scheduler
141
+ The standard scheduler roundrobins queries to evenly to all slaves. This means that if you're using servers with different capacity (slower machines, some slaves receiving traffic from other apps etc) you might run into problems. The weighted scheduler tries to address this by assigning a weight attribute to each slave and distribute queries evenly among the server pool.
142
+
143
+ In your database.yml file add your weights like so:
144
+ test_slave_database_1:
145
+ <<: *creds
146
+ host: my.slavedb_1
147
+ weight: 1
148
+
149
+ test_slave_database_2:
150
+ <<: *creds
151
+ host: my.slavedb_2
152
+ weight: 10
153
+
154
+ The above configuration will lead to slavedb_2 to receive 9 times more queries than slavedb_1. Adding in a new slave with:
155
+ test_slave_database_3:
156
+ <<: *creds
157
+ host: my.slavedb_3
158
+ weight: 5
159
+
160
+ leads to a distribution of 1:10:5. For 100k queries the numbers could look like this:
161
+ Slave 1, with weight 1: 6302 queries
162
+ Slave 2, with weight 10: 62764 queries
163
+ Slave 3, with weight 5: 30934 queries
164
+
165
+ The weighted scheduler does not guarantee that the same slave will not receive two queries in a row. We feel this is not an issue, or rather, that such a guarantee doesn't help much as it's the complexity of the queries rather than the number that creates problems.
166
+
167
+ If no weight param is given for a slave, a weight of 1 is assumed. A weight of 0 is caught and silently transformed into a weight of 1.
168
+
140
169
  === Usage outside of Rails
141
170
 
142
171
  You can use multi_db together with other framworks or in standalone scripts.
@@ -216,6 +245,7 @@ threadsafe and allows sharding of data.
216
245
 
217
246
  === Contributors
218
247
 
248
+ * David Palm http://github.com/dvdplm
219
249
  * Matt Conway http://github.com/wr0ngway
220
250
  * Matthias Marshall http://github.com/webops
221
251
 
@@ -40,7 +40,7 @@ module MultiDb
40
40
 
41
41
  # Replaces the connection of ActiveRecord::Base with a proxy and
42
42
  # establishes the connections to the slaves.
43
- def setup!
43
+ def setup!(scheduler = Scheduler)
44
44
  self.master_models ||= DEFAULT_MASTER_MODELS
45
45
  self.environment ||= (defined?(RAILS_ENV) ? RAILS_ENV : 'development')
46
46
  self.sticky_slave ||= false
@@ -50,10 +50,10 @@ module MultiDb
50
50
  raise "No slaves databases defined for environment: #{self.environment}" if slaves.empty?
51
51
  master.send :include, MultiDb::ActiveRecordExtensions
52
52
  ActiveRecord::Observer.send :include, MultiDb::ObserverExtensions
53
- master.connection_proxy = new(master, slaves)
53
+ master.connection_proxy = new(master, slaves, scheduler)
54
54
  master.logger.info("** multi_db with master and #{slaves.length} slave#{"s" if slaves.length > 1} loaded.")
55
55
  end
56
-
56
+
57
57
  protected
58
58
 
59
59
  # Slave entries in the database.yml must be named like this
@@ -65,12 +65,18 @@ module MultiDb
65
65
  # These would be available later as MultiDb::SlaveDatabaseSomeserver
66
66
  def init_slaves
67
67
  returning([]) do |slaves|
68
- ActiveRecord::Base.configurations.keys.each do |name|
68
+ ActiveRecord::Base.configurations.each do |name, values|
69
69
  if name.to_s =~ /#{self.environment}_(slave_database.*)/
70
+ weight = if values['weight'].blank?
71
+ 1
72
+ else
73
+ (v=values['weight'].to_i.abs).zero?? 1 : v
74
+ end
70
75
  MultiDb.module_eval %Q{
71
76
  class #{$1.camelize} < ActiveRecord::Base
72
77
  self.abstract_class = true
73
78
  establish_connection :#{name}
79
+ WEIGHT = #{weight} unless const_defined?('WEIGHT')
74
80
  end
75
81
  }, __FILE__, __LINE__
76
82
  slaves << "MultiDb::#{$1.camelize}".constantize
@@ -83,8 +89,8 @@ module MultiDb
83
89
 
84
90
  end
85
91
 
86
- def initialize(master, slaves)
87
- @slaves = Scheduler.new(slaves)
92
+ def initialize(master, slaves, scheduler = Scheduler)
93
+ @slaves = scheduler.new(slaves)
88
94
  @master = master
89
95
  @reconnect = false
90
96
  self.current = @slaves.current
@@ -94,6 +100,10 @@ module MultiDb
94
100
  def slave
95
101
  @slaves.current
96
102
  end
103
+
104
+ def scheduler
105
+ @slaves
106
+ end
97
107
 
98
108
  def with_master
99
109
  self.current = @master
data/multi_db.gemspec CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{multi_db}
5
- s.version = "0.2.1"
5
+ s.version = "0.2.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Maximilian Sch\303\266fmann"]
@@ -21,3 +21,22 @@ test_slave_database_2:
21
21
  password:
22
22
  host: 127.0.0.1
23
23
  pool: 5
24
+ weight: 10
25
+
26
+ test_slave_database_3:
27
+ adapter: mysql
28
+ database: multi_db_test
29
+ username: root
30
+ password:
31
+ host: 127.0.0.1
32
+ pool: 5
33
+ weight: 5
34
+
35
+ test_slave_database_4:
36
+ adapter: mysql
37
+ database: multi_db_test
38
+ username: root
39
+ password:
40
+ host: 127.0.0.1
41
+ pool: 5
42
+ weight: 10
@@ -20,210 +20,270 @@ describe MultiDb::ConnectionProxy do
20
20
  @sql = 'SELECT 1 + 1 FROM DUAL'
21
21
  end
22
22
 
23
- before(:each) do
24
- MultiDb::ConnectionProxy.master_models = ['MasterModel']
25
- MultiDb::ConnectionProxy.setup!
26
- @proxy = ActiveRecord::Base.connection_proxy
27
- @master = @proxy.master.retrieve_connection
28
- @slave1 = MultiDb::SlaveDatabase1.retrieve_connection
29
- @slave2 = MultiDb::SlaveDatabase2.retrieve_connection
30
- end
31
-
32
- after(:each) do
33
- ActiveRecord::Base.send :alias_method, :reload, :reload_without_master
34
- end
23
+ describe "with standard Scheduler" do
24
+ before(:each) do
25
+ MultiDb::ConnectionProxy.master_models = ['MasterModel']
26
+ MultiDb::ConnectionProxy.setup!
27
+ @proxy = ActiveRecord::Base.connection_proxy
28
+ @master = @proxy.master.retrieve_connection
29
+ @slave1 = MultiDb::SlaveDatabase1.retrieve_connection
30
+ @slave2 = MultiDb::SlaveDatabase2.retrieve_connection
31
+ @slave3 = MultiDb::SlaveDatabase3.retrieve_connection
32
+ @slave4 = MultiDb::SlaveDatabase4.retrieve_connection
33
+ end
35
34
 
36
- it 'AR::B should respond to #connection_proxy' do
37
- ActiveRecord::Base.connection_proxy.should be_kind_of(MultiDb::ConnectionProxy)
38
- end
35
+ after(:each) do
36
+ ActiveRecord::Base.send :alias_method, :reload, :reload_without_master
37
+ end
38
+
39
+ it 'AR::B should respond to #connection_proxy' do
40
+ ActiveRecord::Base.connection_proxy.should be_kind_of(MultiDb::ConnectionProxy)
41
+ end
39
42
 
40
- it 'FooModel#connection should return an instance of MultiDb::ConnectionProxy' do
41
- FooModel.connection.should be_kind_of(MultiDb::ConnectionProxy)
42
- end
43
+ it 'FooModel#connection should return an instance of MultiDb::ConnectionProxy' do
44
+ FooModel.connection.should be_kind_of(MultiDb::ConnectionProxy)
45
+ end
43
46
 
44
- it 'MasterModel#connection should not return an instance of MultiDb::ConnectionProxy' do
45
- MasterModel.connection.should_not be_kind_of(MultiDb::ConnectionProxy)
46
- end
47
+ it 'MasterModel#connection should not return an instance of MultiDb::ConnectionProxy' do
48
+ MasterModel.connection.should_not be_kind_of(MultiDb::ConnectionProxy)
49
+ end
47
50
 
48
- it "should generate classes for each entry in the database.yml" do
49
- defined?(MultiDb::SlaveDatabase1).should_not be_nil
50
- defined?(MultiDb::SlaveDatabase2).should_not be_nil
51
- end
51
+ it "should generate classes for each entry in the database.yml" do
52
+ defined?(MultiDb::SlaveDatabase1).should_not be_nil
53
+ defined?(MultiDb::SlaveDatabase2).should_not be_nil
54
+ end
52
55
 
53
- it 'should handle nested with_master-blocks correctly' do
54
- @proxy.current.should_not == @proxy.master
55
- @proxy.with_master do
56
- @proxy.current.should == @proxy.master
56
+ it 'should handle nested with_master-blocks correctly' do
57
+ @proxy.current.should_not == @proxy.master
57
58
  @proxy.with_master do
58
59
  @proxy.current.should == @proxy.master
59
60
  @proxy.with_master do
60
61
  @proxy.current.should == @proxy.master
62
+ @proxy.with_master do
63
+ @proxy.current.should == @proxy.master
64
+ end
65
+ @proxy.current.should == @proxy.master
61
66
  end
62
67
  @proxy.current.should == @proxy.master
63
68
  end
64
- @proxy.current.should == @proxy.master
69
+ @proxy.current.should_not == @proxy.master
65
70
  end
66
- @proxy.current.should_not == @proxy.master
67
- end
68
71
 
69
- it 'should perform transactions on the master' do
70
- @master.should_receive(:select_all).exactly(1) # makes sure the first one goes to a slave
71
- @proxy.select_all(@sql)
72
- ActiveRecord::Base.transaction do
72
+ it 'should perform transactions on the master' do
73
+ @master.should_receive(:select_all).exactly(1) # makes sure the first one goes to a slave
73
74
  @proxy.select_all(@sql)
75
+ ActiveRecord::Base.transaction do
76
+ @proxy.select_all(@sql)
77
+ end
74
78
  end
75
- end
76
79
 
77
- it 'should switch to the next reader on selects' do
78
- @slave1.should_receive(:select_one).exactly(2)
79
- @slave2.should_receive(:select_one).exactly(2)
80
- 4.times { @proxy.select_one(@sql) }
81
- end
80
+ it 'should switch to the next reader on selects' do
81
+ @slave1.should_receive(:select_one).exactly(2)
82
+ @slave2.should_receive(:select_one).exactly(2)
83
+ 6.times { @proxy.select_one(@sql) }
84
+ end
82
85
 
83
- it 'should not switch to the next reader when whithin a with_master-block' do
84
- @master.should_receive(:select_one).twice
85
- @slave1.should_not_receive(:select_one)
86
- @slave2.should_not_receive(:select_one)
87
- @proxy.with_master do
88
- 2.times { @proxy.select_one(@sql) }
86
+ it 'should not switch to the next reader when whithin a with_master-block' do
87
+ @master.should_receive(:select_one).twice
88
+ @slave1.should_not_receive(:select_one)
89
+ @slave2.should_not_receive(:select_one)
90
+ @proxy.with_master do
91
+ 2.times { @proxy.select_one(@sql) }
92
+ end
89
93
  end
90
- end
91
94
 
92
- it 'should send dangerous methods to the master' do
93
- meths = [:insert, :update, :delete, :execute]
94
- meths.each do |meth|
95
- @slave1.stub!(meth).and_raise(RuntimeError)
96
- @master.should_receive(meth).and_return(true)
97
- @proxy.send(meth, @sql)
95
+ it 'should send dangerous methods to the master' do
96
+ meths = [:insert, :update, :delete, :execute]
97
+ meths.each do |meth|
98
+ @slave1.stub!(meth).and_raise(RuntimeError)
99
+ @master.should_receive(meth).and_return(true)
100
+ @proxy.send(meth, @sql)
101
+ end
98
102
  end
99
- end
100
103
 
101
- it 'should dynamically generate safe methods' do
102
- @proxy.should_not respond_to(:select_value)
103
- @proxy.select_value(@sql)
104
- @proxy.should respond_to(:select_value)
105
- end
106
-
107
- it 'should cache queries using select_all' do
108
- ActiveRecord::Base.cache do
109
- # next_reader will be called and switch to the SlaveDatabase2
110
- @slave2.should_receive(:select_all).exactly(1)
111
- @slave1.should_not_receive(:select_all)
112
- @master.should_not_receive(:select_all)
113
- 3.times { @proxy.select_all(@sql) }
104
+ it 'should dynamically generate safe methods' do
105
+ @proxy.should_not respond_to(:select_value)
106
+ @proxy.select_value(@sql)
107
+ @proxy.should respond_to(:select_value)
114
108
  end
115
- end
116
109
 
117
- it 'should invalidate the cache on insert, delete and update' do
118
- ActiveRecord::Base.cache do
119
- meths = [:insert, :update, :delete]
120
- meths.each do |meth|
121
- @master.should_receive(meth).and_return(true)
110
+ it 'should cache queries using select_all' do
111
+ ActiveRecord::Base.cache do
112
+ # next_reader will be called and switch to the SlaveDatabase2
113
+ @slave2.should_receive(:select_all).exactly(1)
114
+ @slave1.should_not_receive(:select_all)
115
+ @master.should_not_receive(:select_all)
116
+ 3.times { @proxy.select_all(@sql) }
122
117
  end
123
- @slave2.should_receive(:select_all).twice
124
- @slave1.should_receive(:select_all).once
125
- 3.times do |i|
126
- @proxy.select_all(@sql)
127
- @proxy.send(meths[i])
118
+ end
119
+
120
+ it 'should invalidate the cache on insert, delete and update' do
121
+ ActiveRecord::Base.cache do
122
+ meths = [:insert, :update, :delete, :insert, :update]
123
+ meths.each do |meth|
124
+ @master.should_receive(meth).and_return(true)
125
+ end
126
+ @slave2.should_receive(:select_all).twice
127
+ @slave1.should_receive(:select_all).once
128
+ 5.times do |i|
129
+ @proxy.select_all(@sql)
130
+ @proxy.send(meths[i])
131
+ end
128
132
  end
129
133
  end
130
- end
131
134
 
132
- it 'should retry the next slave when one fails and finally fall back to the master' do
133
- @slave1.should_receive(:select_all).once.and_raise(RuntimeError)
134
- @slave2.should_receive(:select_all).once.and_raise(RuntimeError)
135
- @master.should_receive(:select_all).and_return(true)
136
- @proxy.select_all(@sql)
137
- end
135
+ it 'should retry the next slave when one fails and finally fall back to the master' do
136
+ @slave1.should_receive(:select_all).once.and_raise(RuntimeError)
137
+ @slave2.should_receive(:select_all).once.and_raise(RuntimeError)
138
+ @slave3.should_receive(:select_all).once.and_raise(RuntimeError)
139
+ @slave4.should_receive(:select_all).once.and_raise(RuntimeError)
140
+ @master.should_receive(:select_all).and_return(true)
141
+ @proxy.select_all(@sql)
142
+ end
138
143
 
139
- it 'should try to reconnect the master connection after the master has failed' do
140
- @master.should_receive(:update).and_raise(RuntimeError)
141
- lambda { @proxy.update(@sql) }.should raise_error
142
- @master.should_receive(:reconnect!).and_return(true)
143
- @master.should_receive(:insert).and_return(1)
144
- @proxy.insert(@sql)
145
- end
144
+ it 'should try to reconnect the master connection after the master has failed' do
145
+ @master.should_receive(:update).and_raise(RuntimeError)
146
+ lambda { @proxy.update(@sql) }.should raise_error
147
+ @master.should_receive(:reconnect!).and_return(true)
148
+ @master.should_receive(:insert).and_return(1)
149
+ @proxy.insert(@sql)
150
+ end
146
151
 
147
- it 'should reload models from the master' do
148
- foo = FooModel.create!(:bar => 'baz')
149
- foo.bar = "not_saved"
150
- @slave1.should_not_receive(:select_all)
151
- @slave2.should_not_receive(:select_all)
152
- foo.reload
153
- # we didn't stub @master#select_all here, check that we actually hit the db
154
- foo.bar.should == 'baz'
155
- end
152
+ it 'should reload models from the master' do
153
+ foo = FooModel.create!(:bar => 'baz')
154
+ foo.bar = "not_saved"
155
+ @slave1.should_not_receive(:select_all)
156
+ @slave2.should_not_receive(:select_all)
157
+ foo.reload
158
+ # we didn't stub @master#select_all here, check that we actually hit the db
159
+ foo.bar.should == 'baz'
160
+ end
156
161
 
157
- describe 'with sticky_slave ' do
162
+ describe 'with sticky_slave ' do
158
163
 
159
- before { MultiDb::ConnectionProxy.sticky_slave = true }
160
- after { MultiDb::ConnectionProxy.sticky_slave = false }
164
+ before { MultiDb::ConnectionProxy.sticky_slave = true }
165
+ after { MultiDb::ConnectionProxy.sticky_slave = false }
161
166
 
162
- it 'should not switch to the next reader automatically' do
163
- @slave1.should_receive(:select_all).exactly(3)
164
- @slave2.should_receive(:select_all).exactly(0)
165
- 3.times { @proxy.select_all(@sql) }
166
- end
167
+ it 'should not switch to the next reader automatically' do
168
+ @slave1.should_receive(:select_all).exactly(3)
169
+ @slave2.should_receive(:select_all).exactly(0)
170
+ 3.times { @proxy.select_all(@sql) }
171
+ end
167
172
 
168
- it '#next_reader! should switch to the next slave' do
169
- @slave1.should_receive(:select_one).exactly(3)
170
- @slave2.should_receive(:select_one).exactly(7)
171
- 3.times { @proxy.select_one(@sql) }
172
- @proxy.next_reader!
173
- 7.times { @proxy.select_one(@sql) }
174
- end
173
+ it '#next_reader! should switch to the next slave' do
174
+ @slave1.should_receive(:select_one).exactly(3)
175
+ @slave2.should_receive(:select_one).exactly(7)
176
+ 3.times { @proxy.select_one(@sql) }
177
+ @proxy.next_reader!
178
+ 7.times { @proxy.select_one(@sql) }
179
+ end
175
180
 
176
- end
181
+ end
177
182
 
178
- describe '(accessed from multiple threads)' do
179
- # NOTE: We cannot put expectations on the connection objects itself
180
- # for the threading specs, as connection pooling will cause
181
- # different connections being returned for different threads.
183
+ describe '(accessed from multiple threads)' do
184
+ # NOTE: We cannot put expectations on the connection objects itself
185
+ # for the threading specs, as connection pooling will cause
186
+ # different connections being returned for different threads.
182
187
 
183
- it '#current and #next_reader! should be local to the thread' do
184
- @proxy.current.should == MultiDb::SlaveDatabase1
185
- @proxy.next_reader!.should == MultiDb::SlaveDatabase2
186
- Thread.new do
188
+ it '#current and #next_reader! should be local to the thread' do
187
189
  @proxy.current.should == MultiDb::SlaveDatabase1
188
190
  @proxy.next_reader!.should == MultiDb::SlaveDatabase2
191
+ Thread.new do
192
+ @proxy.current.should == MultiDb::SlaveDatabase1
193
+ @proxy.next_reader!.should == MultiDb::SlaveDatabase2
194
+ @proxy.current.should == MultiDb::SlaveDatabase2
195
+ @proxy.next_reader!.should == MultiDb::SlaveDatabase1
196
+ @proxy.current.should == MultiDb::SlaveDatabase1
197
+ end
189
198
  @proxy.current.should == MultiDb::SlaveDatabase2
190
- @proxy.next_reader!.should == MultiDb::SlaveDatabase1
191
- @proxy.current.should == MultiDb::SlaveDatabase1
192
199
  end
193
- @proxy.current.should == MultiDb::SlaveDatabase2
194
- end
195
200
 
196
- it '#with_master should be local to the thread' do
197
- @proxy.current.should_not == @proxy.master
198
- @proxy.with_master do
199
- @proxy.current.should == @proxy.master
200
- Thread.new do
201
- @proxy.current.should_not == @proxy.master
202
- @proxy.with_master do
203
- @proxy.current.should == @proxy.master
201
+ it '#with_master should be local to the thread' do
202
+ @proxy.current.should_not == @proxy.master
203
+ @proxy.with_master do
204
+ @proxy.current.should == @proxy.master
205
+ Thread.new do
206
+ @proxy.current.should_not == @proxy.master
207
+ @proxy.with_master do
208
+ @proxy.current.should == @proxy.master
209
+ end
210
+ @proxy.current.should_not == @proxy.master
204
211
  end
205
- @proxy.current.should_not == @proxy.master
212
+ @proxy.current.should == @proxy.master
206
213
  end
207
- @proxy.current.should == @proxy.master
214
+ @proxy.current.should_not == @proxy.master
208
215
  end
209
- @proxy.current.should_not == @proxy.master
210
- end
211
216
 
212
- it 'should switch to the next reader even whithin with_master-block in different threads' do
213
- # Because of connection pooling in AR 2.2, the second thread will cause
214
- # a new connection being created behind the scenes. We therefore just test
215
- # that these connections are beting retrieved for the right databases here.
216
- @proxy.master.should_not_receive(:retrieve_connection).and_return(@master)
217
- MultiDb::SlaveDatabase1.should_receive(:retrieve_connection).twice.and_return(@slave1)
218
- MultiDb::SlaveDatabase2.should_receive(:retrieve_connection).once.and_return(@slave2)
219
- @proxy.with_master do
220
- Thread.new do
221
- 3.times { @proxy.select_one(@sql) }
222
- end.join
217
+ it 'should switch to the next reader even whithin with_master-block in different threads' do
218
+ # Because of connection pooling in AR 2.2, the second thread will cause
219
+ # a new connection being created behind the scenes. We therefore just test
220
+ # that these connections are beting retrieved for the right databases here.
221
+ @proxy.master.should_not_receive(:retrieve_connection).and_return(@master)
222
+ MultiDb::SlaveDatabase1.should_receive(:retrieve_connection).twice.and_return(@slave1)
223
+ MultiDb::SlaveDatabase2.should_receive(:retrieve_connection).once.and_return(@slave2)
224
+ MultiDb::SlaveDatabase3.should_receive(:retrieve_connection).once.and_return(@slave3)
225
+ MultiDb::SlaveDatabase4.should_receive(:retrieve_connection).once.and_return(@slave4)
226
+ @proxy.with_master do
227
+ Thread.new do
228
+ 5.times { @proxy.select_one(@sql) }
229
+ end.join
230
+ end
223
231
  end
232
+
224
233
  end
225
234
 
226
- end
235
+ end # with normal scheduler
227
236
 
237
+ describe "alternative scheduler" do
238
+ class MyScheduler
239
+ def initialize(slaves); :done; end
240
+ def current; :current; end
241
+ def next_reader!; :next end
242
+ def blacklist!; :blacklisted; end
243
+ end
244
+
245
+ it "has a 'scheduler' method that returns the current scheduler instance" do
246
+ my_scheduler = mock('My Scheduler!', :current => nil)
247
+ MyScheduler.should_receive(:new).and_return(my_scheduler)
248
+ MultiDb::ConnectionProxy.setup!(MyScheduler)
249
+ ActiveRecord::Base.connection_proxy.should respond_to(:scheduler)
250
+ ActiveRecord::Base.connection_proxy.scheduler.should be(my_scheduler)
251
+ end
252
+
253
+ it "can be initialized with an optional alternative scheduling class" do
254
+ slaves = MultiDb::ConnectionProxy.send(:init_slaves)
255
+ proxy = MultiDb::ConnectionProxy.send(:new, @master, slaves, MyScheduler)
256
+ proxy.scheduler.should be_an_instance_of(MyScheduler)
257
+ end
258
+
259
+ it "uses an alternative scheduler if setup! is called with a compatible class" do
260
+ MultiDb::ConnectionProxy.setup!(MyScheduler)
261
+ ActiveRecord::Base.connection_proxy.scheduler.should be_an_instance_of(MyScheduler)
262
+ end
263
+
264
+ it "uses the default scheduler if no param is passed" do
265
+ MultiDb::ConnectionProxy.setup!
266
+ ActiveRecord::Base.connection_proxy.scheduler.should be_an_instance_of(MultiDb::Scheduler)
267
+ end
268
+
269
+ describe "has weights for query distribution" do
270
+ before do
271
+ MultiDb::ConnectionProxy.setup!
272
+ end
273
+
274
+ it "adds a WEIGHT constant to the MultiDb::SlaveDatabaseN 'models'" do
275
+ MultiDb::SlaveDatabase1.const_defined?('WEIGHT').should be_true
276
+ end
277
+
278
+ it "sets the WEIGHT to 1 if no weight is configured" do
279
+ MultiDb::SlaveDatabase1::WEIGHT.should == 1
280
+ end
281
+
282
+ it "sets the WEIGHT to whatever it is configured to" do
283
+ MultiDb::SlaveDatabase2::WEIGHT.should == 10
284
+ end
285
+ end
286
+
287
+ end # with alternative scheduler
228
288
  end
229
289
 
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'rubygems'
2
- gem 'activerecord', '2.2.2'
2
+ # gem 'activerecord', '2.2.2'
3
3
  %w[tlattr_accessors active_record yaml erb spec].each {|lib| require lib}
4
4
 
5
5
  RAILS_ENV = ENV['RAILS_ENV'] = 'test'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_db
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Maximilian Sch\xC3\xB6fmann"