Class: MultiDb::ConnectionProxy
- Inherits:
-
Object
- Object
- MultiDb::ConnectionProxy
- Extended by:
- ThreadLocalAccessors
- Includes:
- ActiveRecord::ConnectionAdapters::QueryCache, QueryCacheCompat
- Defined in:
- lib/multi_db/connection_proxy.rb
Constant Summary collapse
- SAFE_METHODS =
Safe methods are those that should either go to the slave ONLY or go to the current active connection.
[ :select_all, :select_one, :select_value, :select_values, :select_rows, :select, :verify!, :raw_connection, :active?, :reconnect!, :disconnect!, :reset_runtime, :log, :log_info ]
- DEFAULT_MASTER_MODELS =
['CGI::Session::ActiveRecordStore::Session']
Class Attribute Summary collapse
-
.environment ⇒ Object
defaults to RAILS_ENV if multi_db is used with Rails defaults to ‘development’ when used outside Rails.
-
.master_models ⇒ Object
a list of models that should always go directly to the master.
-
.sticky_slave ⇒ Object
decides if we should switch to the next reader automatically.
Instance Attribute Summary collapse
-
#master ⇒ Object
Returns the value of attribute master.
Class Method Summary collapse
-
.setup! ⇒ Object
Replaces the connection of ActiveRecord::Base with a proxy and establishes the connections to the slaves.
Instance Method Summary collapse
-
#initialize(master, slaves) ⇒ ConnectionProxy
constructor
A new instance of ConnectionProxy.
-
#method_missing(method, *args, &block) ⇒ Object
Calls the method on master/slave and dynamically creates a new method on success to speed up subsequent calls.
-
#next_reader! ⇒ Object
Switches to the next slave database for read operations.
- #slave ⇒ Object
- #transaction(start_db_transaction = true, &block) ⇒ Object
- #with_master ⇒ Object
Methods included from QueryCacheCompat
#columns, #delete, #insert, #select_all, #update
Constructor Details
#initialize(master, slaves) ⇒ ConnectionProxy
Returns a new instance of ConnectionProxy.
88 89 90 91 92 93 94 95 |
# File 'lib/multi_db/connection_proxy.rb', line 88 def initialize(master, slaves) @slaves = Scheduler.new(slaves) @master = master @reconnect = false @config = @master.connection.instance_variable_get("@config") self.current = @slaves.current self.master_depth = 0 end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args, &block) ⇒ Object
Calls the method on master/slave and dynamically creates a new method on success to speed up subsequent calls
116 117 118 119 120 |
# File 'lib/multi_db/connection_proxy.rb', line 116 def method_missing(method, *args, &block) returning(send(target_method(method), method, *args, &block)) do create_delegation_method!(method) end end |
Class Attribute Details
.environment ⇒ Object
defaults to RAILS_ENV if multi_db is used with Rails defaults to ‘development’ when used outside Rails
22 23 24 |
# File 'lib/multi_db/connection_proxy.rb', line 22 def environment @environment end |
.master_models ⇒ Object
a list of models that should always go directly to the master
Example:
MultiDb::ConnectionProxy.master_models = ['MySessionStore', 'PaymentTransaction']
29 30 31 |
# File 'lib/multi_db/connection_proxy.rb', line 29 def master_models @master_models end |
.sticky_slave ⇒ Object
decides if we should switch to the next reader automatically. If set to false, an after|before_filter in the ApplicationController has to do this. This will not affect failover if a master is unavailable.
35 36 37 |
# File 'lib/multi_db/connection_proxy.rb', line 35 def sticky_slave @sticky_slave end |
Instance Attribute Details
#master ⇒ Object
Returns the value of attribute master.
15 16 17 |
# File 'lib/multi_db/connection_proxy.rb', line 15 def master @master end |
Class Method Details
.setup! ⇒ Object
Replaces the connection of ActiveRecord::Base with a proxy and establishes the connections to the slaves.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/multi_db/connection_proxy.rb', line 39 def setup! self.master_models ||= DEFAULT_MASTER_MODELS self.environment ||= (defined?(RAILS_ENV) ? RAILS_ENV : 'development') self.sticky_slave ||= false master = ActiveRecord::Base slaves = init_slaves if slaves.empty? if self.environment == 'development' slaves = [master] else raise "No slaves databases defined for environment: #{self.environment}" end end master.send :include, MultiDb::ActiveRecordExtensions ActiveRecord::Observer.send :include, MultiDb::ObserverExtensions master.connection_proxy = new(master, slaves) master.logger.info("** multi_db with master and #{slaves.length} slave#{"s" if slaves.length > 1} loaded.") end |
Instance Method Details
#next_reader! ⇒ Object
Switches to the next slave database for read operations. Fails over to the master database if all slaves are unavailable.
124 125 126 127 128 129 130 |
# File 'lib/multi_db/connection_proxy.rb', line 124 def next_reader! return unless master_depth.zero? # don't if in with_master block self.current = @slaves.next rescue Scheduler::NoMoreItems logger.warn "[MULTIDB] All slaves are blacklisted. Reading from master" self.current = @master end |
#slave ⇒ Object
97 98 99 |
# File 'lib/multi_db/connection_proxy.rb', line 97 def slave @slaves.current end |
#transaction(start_db_transaction = true, &block) ⇒ Object
110 111 112 |
# File 'lib/multi_db/connection_proxy.rb', line 110 def transaction(start_db_transaction = true, &block) with_master { @master.retrieve_connection.transaction(start_db_transaction, &block) } end |
#with_master ⇒ Object
101 102 103 104 105 106 107 108 |
# File 'lib/multi_db/connection_proxy.rb', line 101 def with_master self.current = @master self.master_depth += 1 yield ensure self.master_depth -= 1 self.current = slave if master_depth.zero? end |