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 =
< Rails 2.3
['CGI::Session::ActiveRecordStore::Session']
Class Attribute Summary collapse
-
.defaults_to_master ⇒ Object
if master should be the default db.
-
.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!(scheduler = Scheduler) ⇒ Object
Replaces the connection of ActiveRecord::Base with a proxy and establishes the connections to the slaves.
Instance Method Summary collapse
-
#initialize(master, slaves, scheduler = Scheduler) ⇒ 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.
- #scheduler ⇒ Object
- #slave ⇒ Object
- #transaction(start_db_transaction = true, &block) ⇒ Object
- #with_master ⇒ Object
- #with_slave ⇒ Object
Methods included from QueryCacheCompat
#columns, #delete, #insert, #select_all, #update
Constructor Details
#initialize(master, slaves, scheduler = Scheduler) ⇒ ConnectionProxy
Returns a new instance of ConnectionProxy.
97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/multi_db/connection_proxy.rb', line 97 def initialize(master, slaves, scheduler = Scheduler) @slaves = scheduler.new(slaves) @master = master @reconnect = false @query_cache = {} if self.class.defaults_to_master self.current = @master self.master_depth = 1 else self.current = @slaves.current self.master_depth = 0 end 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
145 146 147 148 149 |
# File 'lib/multi_db/connection_proxy.rb', line 145 def method_missing(method, *args, &block) send(target_method(method), method, *args, &block).tap do create_delegation_method!(method) end end |
Class Attribute Details
.defaults_to_master ⇒ Object
if master should be the default db
44 45 46 |
# File 'lib/multi_db/connection_proxy.rb', line 44 def defaults_to_master @defaults_to_master end |
.environment ⇒ Object
defaults to Rails.env if multi_db is used with Rails defaults to ‘development’ when used outside Rails
28 29 30 |
# File 'lib/multi_db/connection_proxy.rb', line 28 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']
35 36 37 |
# File 'lib/multi_db/connection_proxy.rb', line 35 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.
41 42 43 |
# File 'lib/multi_db/connection_proxy.rb', line 41 def sticky_slave @sticky_slave end |
Instance Attribute Details
#master ⇒ Object
Returns the value of attribute master.
21 22 23 |
# File 'lib/multi_db/connection_proxy.rb', line 21 def master @master end |
Class Method Details
.setup!(scheduler = Scheduler) ⇒ Object
Replaces the connection of ActiveRecord::Base with a proxy and establishes the connections to the slaves.
48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/multi_db/connection_proxy.rb', line 48 def setup!(scheduler = Scheduler) self.master_models ||= DEFAULT_MASTER_MODELS self.environment ||= (defined?(Rails) ? Rails.env : 'development') self.sticky_slave ||= false master = ActiveRecord::Base slaves = init_slaves raise "No slaves databases defined for environment: #{self.environment}" if slaves.empty? master.send :include, MultiDb::ActiveRecordExtensions ActiveRecord::Observer.send :include, MultiDb::ObserverExtensions master.connection_proxy = new(master, slaves, scheduler) 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.
153 154 155 156 157 158 159 |
# File 'lib/multi_db/connection_proxy.rb', line 153 def next_reader! return if master_depth > 0 # 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 |
#scheduler ⇒ Object
115 116 117 |
# File 'lib/multi_db/connection_proxy.rb', line 115 def scheduler @slaves end |
#slave ⇒ Object
111 112 113 |
# File 'lib/multi_db/connection_proxy.rb', line 111 def slave @slaves.current end |
#transaction(start_db_transaction = true, &block) ⇒ Object
139 140 141 |
# File 'lib/multi_db/connection_proxy.rb', line 139 def transaction(start_db_transaction = true, &block) with_master { @master.retrieve_connection.transaction(start_db_transaction, &block) } end |
#with_master ⇒ Object
120 121 122 123 124 125 126 127 |
# File 'lib/multi_db/connection_proxy.rb', line 120 def with_master self.current = @master self.master_depth += 1 yield ensure self.master_depth -= 1 self.current = slave if (master_depth <= 0) end |
#with_slave ⇒ Object
130 131 132 133 134 135 136 137 |
# File 'lib/multi_db/connection_proxy.rb', line 130 def with_slave self.current = slave self.master_depth -= 1 yield ensure self.master_depth += 1 self.current = @master if (master_depth > 0) end |