Module: ActiveRecordShards::ConnectionSwitcher
- Included in:
- ActiveRecord::Base
- Defined in:
- lib/active_record_shards/connection_switcher.rb,
lib/active_record_shards/connection_switcher-4-2.rb,
lib/active_record_shards/connection_switcher-5-0.rb,
lib/active_record_shards/connection_switcher-5-1.rb,
lib/active_record_shards/connection_switcher-6-0.rb
Defined Under Namespace
Classes: PrimaryReplicaProxy
Constant Summary collapse
- SHARD_NAMES_CONFIG_KEY =
'shard_names'
Class Method Summary collapse
Instance Method Summary collapse
-
#connection_pool_name ⇒ Object
Name of the connection pool.
- #connection_specification_name ⇒ Object
- #current_shard_id ⇒ Object
- #current_shard_selection ⇒ Object
- #default_shard=(new_default_shard) ⇒ Object
- #on_all_shards ⇒ Object
- #on_cx_switch_block(which, force: false, construct_ro_scope: nil, &block) ⇒ Object
- #on_first_shard(&block) ⇒ Object
- #on_primary(&block) ⇒ Object (also: #on_master)
- #on_primary_db(&block) ⇒ Object
- #on_primary_if(condition, &block) ⇒ Object (also: #on_master_if)
- #on_primary_or_replica(which, &block) ⇒ Object (also: #on_master_or_slave)
- #on_primary_unless(condition, &block) ⇒ Object (also: #on_master_unless)
-
#on_replica(&block) ⇒ Object
(also: #on_slave, #with_slave)
Executes queries using the replica database.
- #on_replica? ⇒ Boolean (also: #on_slave?)
- #on_replica_if(condition, &block) ⇒ Object (also: #on_slave_if, #with_slave_if)
- #on_replica_unless(condition, &block) ⇒ Object (also: #on_slave_unless, #with_slave_unless)
- #on_shard(shard) ⇒ Object
- #reset_primary_key_with_default_shard ⇒ Object
- #shard_names ⇒ Object
- #shards ⇒ Object
- #supports_sharding? ⇒ Boolean
Class Method Details
.extended(base) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/active_record_shards/connection_switcher.rb', line 9 def self.extended(base) if ActiveRecord::VERSION::MAJOR >= 5 base.singleton_class.send(:alias_method, :load_schema_without_default_shard!, :load_schema!) base.singleton_class.send(:alias_method, :load_schema!, :load_schema_with_default_shard!) else base.singleton_class.send(:alias_method, :columns_without_default_shard, :columns) base.singleton_class.send(:alias_method, :columns, :columns_with_default_shard) end base.singleton_class.send(:alias_method, :table_exists_without_default_shard?, :table_exists?) base.singleton_class.send(:alias_method, :table_exists?, :table_exists_with_default_shard?) base.singleton_class.send(:alias_method, :reset_primary_key_without_default_shard, :reset_primary_key) base.singleton_class.send(:alias_method, :reset_primary_key, :reset_primary_key_with_default_shard) end |
Instance Method Details
#connection_pool_name ⇒ Object
Name of the connection pool. Used by ConnectionHandler to retrieve the current connection pool.
4 5 6 7 8 9 10 11 12 13 |
# File 'lib/active_record_shards/connection_switcher-4-2.rb', line 4 def connection_pool_name # :nodoc: name = current_shard_selection.shard_name(self) # e.g. if "production_replica" is not defined in `Configuration`, fall back to "production" if configurations[name].nil? && on_replica? current_shard_selection.shard_name(self, false) else name end end |
#connection_specification_name ⇒ Object
3 4 5 6 7 8 9 10 11 |
# File 'lib/active_record_shards/connection_switcher-5-0.rb', line 3 def connection_specification_name name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations) unless configurations[name] || name == "primary" raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.to_h.keys.inspect})" end name end |
#current_shard_id ⇒ Object
154 155 156 |
# File 'lib/active_record_shards/connection_switcher.rb', line 154 def current_shard_id current_shard_selection.shard end |
#current_shard_selection ⇒ Object
150 151 152 |
# File 'lib/active_record_shards/connection_switcher.rb', line 150 def current_shard_selection Thread.current[:shard_selection] ||= ShardSelection.new end |
#default_shard=(new_default_shard) ⇒ Object
25 26 27 28 |
# File 'lib/active_record_shards/connection_switcher.rb', line 25 def default_shard=(new_default_shard) ActiveRecordShards::ShardSelection.default_shard = new_default_shard switch_connection(shard: new_default_shard) end |
#on_all_shards ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/active_record_shards/connection_switcher.rb', line 51 def on_all_shards = current_shard_selection. if supports_sharding? shard_names.map do |shard| switch_connection(shard: shard) yield(shard) end else [yield] end ensure switch_connection() end |
#on_cx_switch_block(which, force: false, construct_ro_scope: nil, &block) ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/active_record_shards/connection_switcher.rb', line 118 def on_cx_switch_block(which, force: false, construct_ro_scope: nil, &block) @disallow_replica ||= 0 @disallow_replica += 1 if [:primary, :master].include?(which) ActiveRecordShards::Deprecation.warn('the `:master` option should be replaced with `:primary`!') if which == :master switch_to_replica = force || @disallow_replica.zero? = current_shard_selection. switch_connection(replica: switch_to_replica) # we avoid_readonly_scope to prevent some stack overflow problems, like when # .columns calls .with_scope which calls .columns and onward, endlessly. if self == ActiveRecord::Base || !switch_to_replica || construct_ro_scope == false || ActiveRecordShards.disable_replica_readonly_records == true yield else readonly.scoping(&block) end ensure @disallow_replica -= 1 if [:primary, :master].include?(which) switch_connection() if end |
#on_first_shard(&block) ⇒ Object
42 43 44 45 |
# File 'lib/active_record_shards/connection_switcher.rb', line 42 def on_first_shard(&block) shard_name = shard_names.first on_shard(shard_name, &block) end |
#on_primary(&block) ⇒ Object Also known as: on_master
108 109 110 |
# File 'lib/active_record_shards/connection_switcher.rb', line 108 def on_primary(&block) on_primary_or_replica(:primary, &block) end |
#on_primary_db(&block) ⇒ Object
30 31 32 |
# File 'lib/active_record_shards/connection_switcher.rb', line 30 def on_primary_db(&block) on_shard(nil, &block) end |
#on_primary_if(condition, &block) ⇒ Object Also known as: on_master_if
75 76 77 |
# File 'lib/active_record_shards/connection_switcher.rb', line 75 def on_primary_if(condition, &block) condition ? on_primary(&block) : yield end |
#on_primary_or_replica(which, &block) ⇒ Object Also known as: on_master_or_slave
85 86 87 88 89 90 91 |
# File 'lib/active_record_shards/connection_switcher.rb', line 85 def on_primary_or_replica(which, &block) if block_given? on_cx_switch_block(which, &block) else PrimaryReplicaProxy.new(self, which) end end |
#on_primary_unless(condition, &block) ⇒ Object Also known as: on_master_unless
80 81 82 |
# File 'lib/active_record_shards/connection_switcher.rb', line 80 def on_primary_unless(condition, &block) on_primary_if(!condition, &block) end |
#on_replica(&block) ⇒ Object Also known as: on_slave, with_slave
Executes queries using the replica database. Fails over to primary if no replica is found. if you want to execute a block of code on the replica you can go:
Account.on_replica do
Account.first
end
the first account will be found on the replica DB
For one-liners you can simply do
Account.on_replica.first
103 104 105 |
# File 'lib/active_record_shards/connection_switcher.rb', line 103 def on_replica(&block) on_primary_or_replica(:replica, &block) end |
#on_replica? ⇒ Boolean Also known as: on_slave?
145 146 147 |
# File 'lib/active_record_shards/connection_switcher.rb', line 145 def on_replica? current_shard_selection.on_replica? end |
#on_replica_if(condition, &block) ⇒ Object Also known as: on_slave_if, with_slave_if
65 66 67 |
# File 'lib/active_record_shards/connection_switcher.rb', line 65 def on_replica_if(condition, &block) condition ? on_replica(&block) : yield end |
#on_replica_unless(condition, &block) ⇒ Object Also known as: on_slave_unless, with_slave_unless
70 71 72 |
# File 'lib/active_record_shards/connection_switcher.rb', line 70 def on_replica_unless(condition, &block) on_replica_if(!condition, &block) end |
#on_shard(shard) ⇒ Object
34 35 36 37 38 39 40 |
# File 'lib/active_record_shards/connection_switcher.rb', line 34 def on_shard(shard) = current_shard_selection. switch_connection(shard: shard) if supports_sharding? yield ensure switch_connection() end |
#reset_primary_key_with_default_shard ⇒ Object
166 167 168 |
# File 'lib/active_record_shards/connection_switcher.rb', line 166 def reset_primary_key_with_default_shard with_default_shard { reset_primary_key_without_default_shard } end |
#shard_names ⇒ Object
158 159 160 161 162 163 164 |
# File 'lib/active_record_shards/connection_switcher.rb', line 158 def shard_names unless config_for_env.fetch(SHARD_NAMES_CONFIG_KEY, []).all? { |shard_name| shard_name.is_a?(Integer) } raise "All shard names must be integers: #{config_for_env[SHARD_NAMES_CONFIG_KEY].inspect}." end config_for_env[SHARD_NAMES_CONFIG_KEY] || [] end |
#shards ⇒ Object
47 48 49 |
# File 'lib/active_record_shards/connection_switcher.rb', line 47 def shards ShardSupport.new(self == ActiveRecord::Base ? nil : where(nil)) end |
#supports_sharding? ⇒ Boolean
141 142 143 |
# File 'lib/active_record_shards/connection_switcher.rb', line 141 def supports_sharding? shard_names.any? end |