slave_pools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT license:
2
+ Copyright (c) 2012 Kickstarter
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,259 @@
1
+ = SlavePools
2
+
3
+ == Easy Single Master/ Multiple Slave Setup for use in Ruby/Rails projects
4
+
5
+ SlavePools builds a base layer of master/slave query splitting, by overwriting ActiveRecord's connection (with connection_proxy). With this in place, you can easily add a second layer of traffic splitting, by wrapping requests in the provided helper methods (examples below), and have a manageable master/slave solution for a standard rails application
6
+
7
+ Overview
8
+ * Sends only whitelisted SELECT-type queries to the Slaves
9
+ * Sends all other queries to the Master
10
+ * Works with query caching and transactions
11
+ * Easy to separate types of read traffic into different collections of slaves (e.g. separating admin and user traffic)
12
+ * Minimalist approach
13
+ * doesn't include sharding
14
+ * doesn't create a new ActiveRecord adapter
15
+ * doesn't weight slave db's
16
+ * Builds onto a standard database.yml file (gem doesn't initialize if no slaves are specified)
17
+ * doesn't switch slaves on its own (the user specifies when to switch in their code)
18
+
19
+ The SlavePools GEM started as a fork of Maximilian Sch\303\266fmann's https://github.com/schoefmax/multi_db
20
+ The MultiDB gem was inspired by Rick Olson's "masochism"-Plugin
21
+
22
+ == Usage
23
+
24
+ Toggle to next slave:
25
+ SlavePools.next_slave!
26
+
27
+ Specify a different slave pool than the default:
28
+ SlavePools.with_pool('other_pool') { #do stuff }
29
+
30
+ Specifically use the master for a call:
31
+ SlavePools.with_master { #do stuff }
32
+
33
+ Determine if there are slaves:
34
+ SlavePools.active?
35
+
36
+ The gem, by default, sends writes and reads to the master and slave databases, respectfully. But in your app, if you write to the master during a request, you will probably want to read from the master in that request as well, in case there is replication. You will also probably want to read from the master on the next request (after a write to the master) to cover redirects.
37
+
38
+ Using a standard rails application setup, you can achieve this by adding these example methods to your application controller (some of these may be folded in the gem, but leaving out for now):
39
+
40
+ class ApplicationController < ActionController::Base
41
+
42
+ around_filter :stick_to_master_for_updates
43
+ around_filter :use_master_for_redirect #goes with above
44
+ after_filter :switch_to_next_slave
45
+
46
+ def switch_to_next_slave
47
+ SlavePools.next_slave! if slaves?
48
+ end
49
+
50
+ def use_admin_slave_pool
51
+ SlavePools.with_pool('admin') { yield } if slaves?
52
+ end
53
+
54
+ def stick_to_master_for_updates
55
+ if slaves? && (request.post? || request.put? || request.delete?)
56
+ SlavePools.with_master { yield }
57
+ session[:stick_to_master] = 1
58
+ else
59
+ yield
60
+ end
61
+ end
62
+
63
+ def use_master_for_redirect
64
+ if slaves? && session[:stick_to_master]
65
+ session[:stick_to_master] = nil
66
+ SlavePools.with_master { yield }
67
+ else
68
+ yield
69
+ end
70
+ end
71
+
72
+ def use_master
73
+ if slaves?
74
+ SlavePools.with_master { yield }
75
+ session[:stick_to_master] = 1
76
+ else
77
+ yield
78
+ end
79
+ end
80
+
81
+ def slaves?
82
+ SlavePools.active?
83
+ end
84
+ end
85
+
86
+ For other cases where you use the master for writes, you should wrap the request in a 'use_master' block
87
+
88
+ class PostsController < ApplicationController
89
+ around_filter :use_master, :only=>:index
90
+
91
+ def index
92
+ Activity.create()
93
+ # index is a GET call, but we've decided to record something, so we want to wrap it in a use_master block
94
+ end
95
+ end
96
+
97
+ * works with activerecord 3.2.12 (not tested with Rails 2)
98
+
99
+ === Install
100
+
101
+ Add to your Gemfile
102
+
103
+ gem 'slave_pools'
104
+
105
+ === Setup
106
+
107
+ slave_pools identifies slave databases by looking for entries of the form
108
+ "<tt><environment>_pool_<pool_name>_name_<db_name></tt>".
109
+
110
+ In your database.yml, add sections for the slaves, e.g.:
111
+
112
+ development: # that would be the master
113
+ adapter: mysql
114
+ database: myapp_production
115
+ username: root
116
+ password:
117
+ host: localhost
118
+
119
+ development_pool_default_name_slave1: # that would be a slave named 'slave1' in the 'default' pool
120
+ adapter: mysql
121
+ database: slave_db1
122
+ username: root
123
+ password:
124
+ host: 10.0.0.2
125
+
126
+ development_pool_default_name_slave2: # that would be a slave named 'slave2' in the 'default' pool
127
+ ...
128
+ development_pool_admin_name_slave1: # that would be a slave named 'slave1' in the 'admin' pool (db names can be reused across pools)
129
+ ...
130
+ development_pool_admin_name_another_slave: # that would be a slave named 'another_slave' in the 'admin' pool
131
+
132
+ This also creates an abstract classes named <tt>SlavePools::DefaultDb1</tt> for each db of the form <tt>SlavePools::<PoolName><DbName></tt>etc. If no slaves are specified, the SlavePools setup does not run, and the development DB would be used as normal.
133
+
134
+ For development testing, I recommend creating a read-only mysql user and just point all of your slave DB's to the your development DB using the read-only user.
135
+
136
+ The Default SlavePool will be used for all requests, so you should name on of the pools 'default' (if there isn't a 'default' slave_pool, the first slave_pool specified becomes the default)
137
+
138
+ To enable the proxy globally, add this to a config/initializers:
139
+
140
+ SlavePools.setup!
141
+
142
+ If you only want to enable it for specific environments, add this to
143
+ the corresponding file in config/environments:
144
+
145
+ config.after_initialize do
146
+ SlavePools.setup!
147
+ end
148
+
149
+
150
+ === Using with Phusion Passenger
151
+
152
+ (this is a note from MultiDB gem and has not been verified)
153
+
154
+ With Passengers smart spawning method, child processes forked by the ApplicationSpawner
155
+ won't have the connection proxy set up properly (this is a note from ).
156
+
157
+ To make it work, add this to your <tt>environment.rb</tt> or an initializer script
158
+ (e.g. <tt>config/initializers/connection_proxy.rb</tt>):
159
+
160
+ if defined?(PhusionPassenger)
161
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
162
+ if forked
163
+ # ... set configuration options, if any ...
164
+ SlavePools::ConnectionProxy.setup!
165
+ end
166
+ end
167
+ else # not using passenger (e.g. development/testing)
168
+ # ... set configuration options, if any ...
169
+ SlavePools::ConnectionProxy.setup!
170
+ end
171
+
172
+ === Using with ThinkingSphinx
173
+
174
+ ThinkingSphinx looks for an adapter type and
175
+ SlavePools::ConnectionProxy.setup!
176
+
177
+ if ActiveRecord::Base.respond_to?('connection_proxy')
178
+ ThinkingSphinx::AbstractAdapter.class_eval do
179
+ def self.standard_adapter_for_model(model)
180
+ :mysql
181
+ end
182
+ end
183
+ end
184
+
185
+ === Forcing the master for certain actions
186
+
187
+ Just add this to your controller:
188
+
189
+ around_filter(:only => :foo_action) { |c,a| ActiveRecord::Base.connection_proxy.with_master { a.call } }
190
+
191
+ === Forcing the master for certain models
192
+
193
+ In your environment.rb or an initializer, add this *before* the call to <tt>setup!</tt>:
194
+
195
+ SlavePoolsModule::ConnectionProxy.master_models = ['CGI::Session::ActiveRecordStore::Session', 'PaymentTransaction', ...]
196
+ SlavePoolsModule::ConnectionProxy.setup!
197
+
198
+ *NOTE*: You cannot safely add more master_models after calling <tt>setup!</tt>.
199
+ === Features
200
+ * Minimalist implementation - does include sharding, doesn't creation a new adapter (so if you don't specify slaves for
201
+ an environment, the connection is not overwritten, and the DB works as normal), doesn't blacklist/remove slaves,
202
+ * It sends everything except "select ..." queries to the master, instead of
203
+ sending only specific things to the master and anything "else" to the slave.
204
+ This avoids accidental writes to the master when there are API changes in
205
+ ActiveRecord which haven't been picked up by multi_db yet.
206
+ Note that this behavior will also always send helper methods like "+quote+" or
207
+ "<tt>add_limit!</tt>" to the master connection object, which doesn't add any
208
+ more load on the master, as these methods don't communicate with the db server
209
+ itself.
210
+
211
+
212
+ === Differences to "multi_db":
213
+
214
+ * Supports multiple separate pools of slave databases
215
+ * query caching is fixed
216
+ * tries a slave once and immediately reverts to the master afterwards (does not cycle through slaves)
217
+ * stays with the same slave DB until explicitly told to change. In practical usage, it didn't make sense to us
218
+ to have it cycle through slaves in the same web request, so I made the 'sticky slave' feature permanent
219
+ * removed weighted slave rotation for now (didn't need it)
220
+ * Currently not using Threaded variables (left this commented out in the code for now, may revisit)
221
+ * Added with_pool method
222
+ * does not blacklist slaves for timing out (we want other more robust monitoring software to take care of this)
223
+ * better default case handling - if no slave DB's are specified, the regular Environment database is used, and the gem is
224
+ not initialized
225
+ * added a wrapper class for shorter calls
226
+
227
+ === See also
228
+
229
+ ===== Masochism
230
+
231
+ The original master/slave plugin:
232
+
233
+ * http://github.com/technoweenie/masochism
234
+
235
+ ===== MultiDb
236
+
237
+ The project is based on:
238
+
239
+ * https://github.com/schoefmax/multi_db
240
+
241
+ === Running specs
242
+
243
+ If you haven't already, install the rspec gem, then set up your database
244
+ with a test database and a read_only user.
245
+
246
+ To match spec/config/database.yml, you can:
247
+
248
+ mysql>
249
+ create database test_db;
250
+ create user 'read_only'@'localhost' identified by 'readme';
251
+ grant select on db_test.* to 'read_only'@'localhost';
252
+
253
+ From the plugin directory, run:
254
+
255
+ rspec spec
256
+
257
+ Author: Dan Drabik
258
+ Copyright (c) 2012, Kickstarter
259
+ Released under the MIT license
@@ -0,0 +1,43 @@
1
+ require 'active_record'
2
+ require 'slave_pools/slave_pool'
3
+ require 'slave_pools/active_record_extensions'
4
+ require 'slave_pools/observer_extensions'
5
+ require 'slave_pools/query_cache_compat'
6
+ require 'slave_pools/connection_proxy'
7
+
8
+ #wrapper class to make the calls more succinct
9
+
10
+ class SlavePools
11
+
12
+ def self.setup!
13
+ SlavePoolsModule::ConnectionProxy.setup!
14
+ end
15
+
16
+ def self.active?
17
+ ActiveRecord::Base.respond_to?('connection_proxy')
18
+ end
19
+
20
+ def self.next_slave!
21
+ ActiveRecord::Base.connection_proxy.next_slave! if active?
22
+ end
23
+
24
+ def self.with_pool(pool_name = 'default')
25
+ if active?
26
+ ActiveRecord::Base.connection_proxy.with_pool(pool_name) { yield }
27
+ else
28
+ yield
29
+ end
30
+ end
31
+
32
+ def self.with_master
33
+ if active?
34
+ ActiveRecord::Base.connection_proxy.with_master { yield }
35
+ else
36
+ yield
37
+ end
38
+ end
39
+
40
+ def self.current
41
+ ActiveRecord::Base.connection_proxy.current if active?
42
+ end
43
+ end
@@ -0,0 +1,54 @@
1
+ module SlavePoolsModule
2
+ module ActiveRecordExtensions
3
+ def self.included(base)
4
+ base.send :include, InstanceMethods
5
+ base.send :extend, ClassMethods
6
+ base.cattr_accessor :connection_proxy
7
+ # handle subclasses which were defined by the framework or plugins
8
+ base.send(:descendants).each do |child|
9
+ child.hijack_connection
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def reload(options = nil)
15
+ self.connection_proxy.with_master { super }
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ # Make sure transactions always switch to the master
21
+ def transaction(options = {}, &block)
22
+ if self.connection.kind_of?(ConnectionProxy)
23
+ super
24
+ else
25
+ self.connection_proxy.with_master { super }
26
+ end
27
+ end
28
+
29
+ # Make sure caching always uses master connection
30
+ def cache(&block)
31
+ if ActiveRecord::Base.configurations.blank?
32
+ yield
33
+ else
34
+ ActiveRecord::Base.connection.cache(&block)
35
+ end
36
+ end
37
+
38
+ def inherited(child)
39
+ super
40
+ child.hijack_connection
41
+ end
42
+
43
+ def hijack_connection
44
+ return if ConnectionProxy.master_models.include?(self.to_s)
45
+ # logger.info "[SlavePools] hijacking connection for #{self.to_s}" # commenting out noisy logging
46
+ class << self
47
+ def connection
48
+ self.connection_proxy
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,280 @@
1
+ require 'active_record/connection_adapters/abstract/query_cache'
2
+ require 'set'
3
+
4
+ module SlavePoolsModule
5
+ class ConnectionProxy
6
+ include ActiveRecord::ConnectionAdapters::QueryCache
7
+ include QueryCacheCompat
8
+
9
+ # Safe methods are those that should either go to the slave ONLY or go
10
+ # to the current active connection.
11
+ SAFE_METHODS = Set.new([ :select_all, :select_one, :select_value, :select_values,
12
+ :select_rows, :select, :verify!, :raw_connection, :active?, :reconnect!,
13
+ :disconnect!, :reset_runtime, :log, :log_info ])
14
+
15
+ if ActiveRecord.const_defined?(:SessionStore) # >= Rails 2.3
16
+ DEFAULT_MASTER_MODELS = ['ActiveRecord::SessionStore::Session']
17
+ else # =< Rails 2.3
18
+ DEFAULT_MASTER_MODELS = ['CGI::Session::ActiveRecordStore::Session']
19
+ end
20
+
21
+ attr_accessor :master
22
+ attr_accessor :master_depth, :current, :current_pool
23
+
24
+ class << self
25
+
26
+ # defaults to Rails.env if multi_db is used with Rails
27
+ # defaults to 'development' when used outside Rails
28
+ attr_accessor :environment
29
+
30
+ # a list of models that should always go directly to the master
31
+ #
32
+ # Example:
33
+ #
34
+ # SlavePool::ConnectionProxy.master_models = ['MySessionStore', 'PaymentTransaction']
35
+ attr_accessor :master_models
36
+
37
+ #true or false - whether you want to include the ActionController helpers or not
38
+ #this allow
39
+
40
+ # if master should be the default db
41
+ attr_accessor :defaults_to_master
42
+
43
+ # #setting a config instance variable so that thinking sphinx,and other gems that use the connection.instance_variable_get(:@config), work correctly
44
+ attr_accessor :config
45
+
46
+ # Replaces the connection of ActiveRecord::Base with a proxy and
47
+ # establishes the connections to the slaves.
48
+ def setup!
49
+ self.master_models ||= DEFAULT_MASTER_MODELS
50
+ self.environment ||= (defined?(Rails.env) ? Rails.env : 'development')
51
+
52
+ slave_pools = init_slave_pools
53
+ # if there are no slave pools, we just want to silently exit and not edit the ActiveRecord::Base.connection
54
+ if !slave_pools.empty?
55
+ master = ActiveRecord::Base
56
+ master.send :include, SlavePoolsModule::ActiveRecordExtensions
57
+ ActiveRecord::Observer.send :include, SlavePoolsModule::ObserverExtensions
58
+
59
+ master.connection_proxy = new(master, slave_pools)
60
+ master.logger.info("** slave_pools with master and #{slave_pools.length} slave_pool#{"s" if slave_pools.length > 1} (#{slave_pools.keys}) loaded.")
61
+ else
62
+ ActiveRecord::Base.logger.info(" No Slave Pools specified for this environment") #this is currently not logging
63
+ end
64
+ end
65
+
66
+ protected
67
+
68
+ def init_slave_pools
69
+ slave_pools = {}
70
+ ActiveRecord::Base.configurations.each do |name, db_config|
71
+ # look for dbs matching the slave_pool format and verify a test connection before adding it to the pools
72
+ if name.to_s =~ /#{self.environment}_pool_(.*)_name_(.*)/ && connection_valid?(db_config)
73
+ slave_pools = add_to_pool(slave_pools, $1, $2, name, db_config)
74
+ end
75
+ end
76
+ return slave_pools
77
+ end
78
+
79
+ private :new
80
+
81
+ end # end class << self
82
+
83
+ def initialize(master, slave_pools)
84
+ @slave_pools = {}
85
+ slave_pools.each do |pool_name, slaves|
86
+ @slave_pools[pool_name.to_sym] = SlavePool.new(pool_name, slaves)
87
+ end
88
+ @master = master
89
+ @reconnect = false
90
+ @current_pool = default_pool
91
+ if self.class.defaults_to_master
92
+ @current = @master
93
+ @master_depth = 1
94
+ @config = master.connection.instance_variable_get(:@config)
95
+ else
96
+ @current = slave
97
+ @master_depth = 0
98
+ @config = @current.config_hash #setting this
99
+ end
100
+
101
+ end
102
+
103
+ def default_pool
104
+ @slave_pools[:default] || @slave_pools.values.first #if there is no default specified, use the first pool found
105
+ end
106
+
107
+ def slave_pools
108
+ @slave_pools
109
+ end
110
+
111
+ def slave
112
+ @current_pool.current
113
+ end
114
+
115
+ def with_pool(pool_name = 'default')
116
+ @current_pool = @slave_pools[pool_name.to_sym] || default_pool
117
+ @current = slave unless within_master_block?
118
+ yield
119
+ ensure
120
+ @current_pool = default_pool
121
+ @current = slave unless within_master_block?
122
+ end
123
+
124
+ def with_master
125
+ @current = @master
126
+ @master_depth += 1
127
+ yield
128
+ ensure
129
+ @master_depth -= 1
130
+ @master_depth = 0 if @master_depth < 0 # ensure that master depth never gets below 0
131
+ @current = slave if !within_master_block?
132
+ end
133
+
134
+ def within_master_block?
135
+ @master_depth > 0
136
+ end
137
+
138
+ def transaction(start_db_transaction = true, &block)
139
+ with_master { @master.retrieve_connection.transaction(start_db_transaction, &block) }
140
+ end
141
+
142
+ # Calls the method on master/slave and dynamically creates a new
143
+ # method on success to speed up subsequent calls
144
+ def method_missing(method, *args, &block)
145
+ send(target_method(method), method, *args, &block).tap do
146
+ create_delegation_method!(method)
147
+ end
148
+ end
149
+
150
+ # Switches to the next slave database for read operations.
151
+ # Fails over to the master database if all slaves are unavailable.
152
+ def next_slave!
153
+ return if within_master_block? # don't if in with_master block
154
+ @current = @current_pool.next
155
+ rescue
156
+ @current = @master
157
+ end
158
+
159
+ protected
160
+
161
+ def create_delegation_method!(method)
162
+ self.instance_eval %Q{
163
+ def #{method}(*args, &block)
164
+ #{target_method(method)}(:#{method}, *args, &block)
165
+ end
166
+ }, __FILE__, __LINE__
167
+ end
168
+
169
+ def target_method(method)
170
+ unsafe?(method) ? :send_to_master : :send_to_current
171
+ end
172
+
173
+ def send_to_master(method, *args, &block)
174
+ reconnect_master! if @reconnect
175
+ @master.retrieve_connection.send(method, *args, &block)
176
+ rescue => e
177
+ log_errors(e, 'send_to_master', method)
178
+ raise_master_error(e)
179
+ end
180
+
181
+ def send_to_current(method, *args, &block)
182
+ reconnect_master! if @reconnect && master?
183
+ # logger.debug "[SlavePools] Using #{@current.name}"
184
+ @current = @master if unsafe?(method) #failsafe to avoid sending dangerous method to master
185
+ @current.retrieve_connection.send(method, *args, &block)
186
+ rescue Mysql2::Error, ActiveRecord::StatementInvalid => e
187
+ log_errors(e, 'send_to_current', method)
188
+ raise_master_error(e) if master?
189
+ logger.warn "[SlavePools] Error reading from slave database"
190
+ logger.error %(#{e.message}\n#{e.backtrace.join("\n")})
191
+ if e.message.match(/Timeout waiting for a response from the last query/)
192
+ # Verify that the connection is active & re-raise
193
+ @current.retrieve_connection.verify!
194
+ raise e
195
+ else
196
+ send_to_master(method, *args, &block) # if cant connect, send the query to master
197
+ end
198
+ end
199
+
200
+ def reconnect_master!
201
+ @master.retrieve_connection.reconnect!
202
+ @reconnect = false
203
+ end
204
+
205
+ def raise_master_error(error)
206
+ logger.fatal "[SlavePools] Error accessing master database. Scheduling reconnect"
207
+ @reconnect = true
208
+ raise error
209
+ end
210
+
211
+ def unsafe?(method)
212
+ !SAFE_METHODS.include?(method)
213
+ end
214
+
215
+ def master?
216
+ @current == @master
217
+ end
218
+
219
+ def logger
220
+ ActiveRecord::Base.logger
221
+ end
222
+
223
+ private
224
+
225
+ def self.add_to_pool(slave_pools, pool_name, slave_name, full_db_name, db_config)
226
+ slave_pools[pool_name] ||= []
227
+ db_config_with_symbols = db_config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
228
+ SlavePoolsModule.module_eval %Q{
229
+ class #{pool_name.camelize}#{slave_name.camelize} < ActiveRecord::Base
230
+ self.abstract_class = true
231
+ establish_connection :#{full_db_name}
232
+ def self.config_hash
233
+ #{db_config_with_symbols.inspect}
234
+ end
235
+ end
236
+ }, __FILE__, __LINE__
237
+ slave_pools[pool_name] << "SlavePoolsModule::#{pool_name.camelize}#{slave_name.camelize}".constantize
238
+ return slave_pools
239
+ end
240
+
241
+ # method to verify whether DB connection is active?
242
+ def self.connection_valid?(db_config = nil)
243
+ is_connected = false
244
+ if db_config
245
+ begin
246
+ ActiveRecord::Base.establish_connection(db_config)
247
+ ActiveRecord::Base.connection
248
+ is_connected = ActiveRecord::Base.connected?
249
+ rescue => e
250
+ log_errors(e, 'self.connection_valid?')
251
+ ensure
252
+ ActiveRecord::Base.establish_connection(environment) #rollback to the current environment to avoid issues
253
+ end
254
+ end
255
+ return is_connected
256
+ end
257
+
258
+ # logging instance errors
259
+ def log_errors(error, sp_method, db_method)
260
+ logger.error "[SlavePools] - Error: #{error}"
261
+ logger.error "[SlavePools] - SlavePool Method: #{sp_method}"
262
+ logger.error "[SlavePools] - Master Value: #{@master}"
263
+ logger.error "[SlavePools] - Master Depth: #{@master_depth}"
264
+ logger.error "[SlavePools] - Current Value: #{@current}"
265
+ logger.error "[SlavePools] - Current Pool: #{@current_pool}"
266
+ logger.error "[SlavePools] - Current Pool Slaves: #{@current_pool.slaves}" if @current_pool
267
+ logger.error "[SlavePools] - Current Pool Name: #{@current_pool.name}" if @current_pool
268
+ logger.error "[SlavePools] - Reconnect Value: #{@reconnect}"
269
+ logger.error "[SlavePools] - Default Pool: #{default_pool}"
270
+ logger.error "[SlavePools] - DB Method: #{db_method}"
271
+ end
272
+
273
+ # logging class errors
274
+ def self.log_errors(error, sp_method)
275
+ logger = ActiveRecord::Base.logger
276
+ logger.error "[SlavePools] - Error: #{error}"
277
+ logger.error "[SlavePools] - SlavePool Method: #{sp_method}"
278
+ end
279
+ end
280
+ end