active_record_shards 3.19.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -2
- data/lib/active_record_shards/association_collection_connection_selection.rb +1 -8
- data/lib/active_record_shards/configuration_parser.rb +1 -9
- data/lib/active_record_shards/connection_switcher-5-1.rb +1 -1
- data/lib/active_record_shards/{connection_switcher-5-0.rb → connection_switcher-6-0.rb} +8 -7
- data/lib/active_record_shards/connection_switcher.rb +28 -50
- data/lib/active_record_shards/default_replica_patches.rb +3 -44
- data/lib/active_record_shards/migration.rb +2 -3
- data/lib/active_record_shards/model.rb +0 -4
- data/lib/active_record_shards/shard_selection.rb +22 -55
- data/lib/active_record_shards/shard_support.rb +5 -6
- data/lib/active_record_shards/tasks.rb +9 -11
- data/lib/active_record_shards.rb +7 -69
- metadata +9 -16
- data/lib/active_record_shards/connection_handler.rb +0 -8
- data/lib/active_record_shards/connection_pool.rb +0 -36
- data/lib/active_record_shards/connection_specification.rb +0 -19
- data/lib/active_record_shards/connection_switcher-4-2.rb +0 -56
- data/lib/active_record_shards/default_slave_patches.rb +0 -5
- data/lib/active_record_shards/deprecation.rb +0 -12
- data/lib/active_record_shards/patches-4-2.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07a2ae4e9b397abcc455655266c9d66c76af160e56ea963b401a130589f3f48c
|
4
|
+
data.tar.gz: 45993e917fb0585637c72f89d6bee77f805e0192efb6ca3f476e86929d9192ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16309006259fadb5b3851ea470d8859618c2df4d10555e5ecb50c257d538ac3f36c69490a33547bc7e53e6a2962d5985623176021b5f0866f9a35973138000cc
|
7
|
+
data.tar.gz: d23f2ae22180be953ba4a8bbb23000f73901ecf7950cae95858d371eec24bf01f2e7d6ee0c7225e8bbe2f76490261baae4059193718ae3cb17ffd78ab338f852
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
ActiveRecord Shards is an extension for ActiveRecord that provides support for sharded database and replicas. Basically it is just a nice way to
|
6
6
|
switch between database connections. We've made the implementation very small, and have tried not to reinvent any wheels already present in ActiveRecord.
|
7
7
|
|
8
|
-
ActiveRecord Shards has been used and tested on Rails
|
8
|
+
ActiveRecord Shards has been used and tested on Rails 5.x and 6.0, and has in some form or another been used in production on large Rails apps for several years.
|
9
9
|
|
10
10
|
- [Installation](#installation)
|
11
11
|
- [Configuration](#configuration)
|
@@ -148,12 +148,16 @@ ActiveRecord::Base.on_replica do
|
|
148
148
|
end
|
149
149
|
```
|
150
150
|
|
151
|
-
This will perform the query on the replica, and mark the returned instances as read
|
151
|
+
This will perform the query on the replica, and mark the returned instances as read-only. There is also a shortcut for this:
|
152
152
|
|
153
153
|
```ruby
|
154
154
|
Account.on_replica.find_by_big_expensive_query
|
155
155
|
```
|
156
156
|
|
157
|
+
If you do not want instances returned from replicas to be marked as read-only, this can be disabled globally:
|
158
|
+
|
159
|
+
`ActiveRecordShards.disable_replica_readonly_records = true`
|
160
|
+
|
157
161
|
## Debugging
|
158
162
|
|
159
163
|
Show if a query went to primary or replica in the logs:
|
@@ -5,32 +5,26 @@ module ActiveRecordShards
|
|
5
5
|
def on_replica_if(condition)
|
6
6
|
condition ? on_replica : self
|
7
7
|
end
|
8
|
-
alias_method :on_slave_if, :on_replica_if
|
9
8
|
|
10
9
|
def on_replica_unless(condition)
|
11
10
|
on_replica_if(!condition)
|
12
11
|
end
|
13
|
-
alias_method :on_slave_unless, :on_replica_unless
|
14
12
|
|
15
13
|
def on_primary_if(condition)
|
16
14
|
condition ? on_primary : self
|
17
15
|
end
|
18
|
-
alias_method :on_master_if, :on_primary_if
|
19
16
|
|
20
17
|
def on_primary_unless(condition)
|
21
18
|
on_primary_if(!condition)
|
22
19
|
end
|
23
|
-
alias_method :on_master_unless, :on_primary_unless
|
24
20
|
|
25
21
|
def on_replica
|
26
22
|
PrimaryReplicaProxy.new(self, :replica)
|
27
23
|
end
|
28
|
-
alias_method :on_slave, :on_replica
|
29
24
|
|
30
25
|
def on_primary
|
31
26
|
PrimaryReplicaProxy.new(self, :primary)
|
32
27
|
end
|
33
|
-
alias_method :on_master, :on_primary
|
34
28
|
|
35
29
|
class PrimaryReplicaProxy
|
36
30
|
def initialize(association_collection, which)
|
@@ -42,8 +36,7 @@ module ActiveRecordShards
|
|
42
36
|
reflection = @association_collection.proxy_association.reflection
|
43
37
|
reflection.klass.on_cx_switch_block(@which) { @association_collection.send(method, *args, &block) }
|
44
38
|
end
|
39
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
45
40
|
end
|
46
|
-
|
47
|
-
MasterSlaveProxy = PrimaryReplicaProxy
|
48
41
|
end
|
49
42
|
end
|
@@ -28,14 +28,6 @@ module ActiveRecordShards
|
|
28
28
|
expand_child!(env_config, replica_conf)
|
29
29
|
conf["#{env_name}_replica"] = replica_conf
|
30
30
|
end
|
31
|
-
|
32
|
-
# rubocop:disable Style/Next
|
33
|
-
if legacy_replica_conf = env_config.delete('slave')
|
34
|
-
ActiveRecordShards::Deprecation.warn('`slave` configuration keys should be replaced with `replica` keys!')
|
35
|
-
expand_child!(env_config, legacy_replica_conf)
|
36
|
-
conf["#{env_name}_replica"] = legacy_replica_conf
|
37
|
-
end
|
38
|
-
# rubocop:enable Style/Next
|
39
31
|
end
|
40
32
|
|
41
33
|
conf
|
@@ -43,7 +35,7 @@ module ActiveRecordShards
|
|
43
35
|
|
44
36
|
def expand_child!(parent, child)
|
45
37
|
parent.each do |key, value|
|
46
|
-
unless ['
|
38
|
+
unless ['replica', 'shards'].include?(key) || value.is_a?(Hash)
|
47
39
|
child[key] ||= value
|
48
40
|
end
|
49
41
|
end
|
@@ -4,7 +4,7 @@ module ActiveRecordShards
|
|
4
4
|
name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
|
5
5
|
|
6
6
|
unless configurations[name] || name == "primary"
|
7
|
-
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.keys.inspect})"
|
7
|
+
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.to_h.keys.inspect})"
|
8
8
|
end
|
9
9
|
|
10
10
|
name
|
@@ -3,8 +3,13 @@ module ActiveRecordShards
|
|
3
3
|
def connection_specification_name
|
4
4
|
name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
@_ars_connection_specification_names ||= {}
|
7
|
+
unless @_ars_connection_specification_names.include?(name)
|
8
|
+
unless configurations[name] || name == "primary"
|
9
|
+
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.to_h.keys.inspect})"
|
10
|
+
end
|
11
|
+
|
12
|
+
@_ars_connection_specification_names[name] = true
|
8
13
|
end
|
9
14
|
|
10
15
|
name
|
@@ -19,11 +24,7 @@ module ActiveRecordShards
|
|
19
24
|
spec_name = connection_specification_name
|
20
25
|
|
21
26
|
pool = connection_handler.retrieve_connection_pool(spec_name)
|
22
|
-
if pool.nil?
|
23
|
-
resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configurations)
|
24
|
-
spec = resolver.spec(spec_name.to_sym, spec_name)
|
25
|
-
connection_handler.establish_connection(spec)
|
26
|
-
end
|
27
|
+
connection_handler.establish_connection(spec_name.to_sym) if pool.nil?
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
@@ -7,13 +7,8 @@ module ActiveRecordShards
|
|
7
7
|
SHARD_NAMES_CONFIG_KEY = 'shard_names'
|
8
8
|
|
9
9
|
def self.extended(base)
|
10
|
-
|
11
|
-
|
12
|
-
base.singleton_class.send(:alias_method, :load_schema!, :load_schema_with_default_shard!)
|
13
|
-
else
|
14
|
-
base.singleton_class.send(:alias_method, :columns_without_default_shard, :columns)
|
15
|
-
base.singleton_class.send(:alias_method, :columns, :columns_with_default_shard)
|
16
|
-
end
|
10
|
+
base.singleton_class.send(:alias_method, :load_schema_without_default_shard!, :load_schema!)
|
11
|
+
base.singleton_class.send(:alias_method, :load_schema!, :load_schema_with_default_shard!)
|
17
12
|
|
18
13
|
base.singleton_class.send(:alias_method, :table_exists_without_default_shard?, :table_exists?)
|
19
14
|
base.singleton_class.send(:alias_method, :table_exists?, :table_exists_with_default_shard?)
|
@@ -62,22 +57,18 @@ module ActiveRecordShards
|
|
62
57
|
def on_replica_if(condition, &block)
|
63
58
|
condition ? on_replica(&block) : yield
|
64
59
|
end
|
65
|
-
alias_method :on_slave_if, :on_replica_if
|
66
60
|
|
67
61
|
def on_replica_unless(condition, &block)
|
68
62
|
on_replica_if(!condition, &block)
|
69
63
|
end
|
70
|
-
alias_method :on_slave_unless, :on_replica_unless
|
71
64
|
|
72
65
|
def on_primary_if(condition, &block)
|
73
66
|
condition ? on_primary(&block) : yield
|
74
67
|
end
|
75
|
-
alias_method :on_master_if, :on_primary_if
|
76
68
|
|
77
69
|
def on_primary_unless(condition, &block)
|
78
70
|
on_primary_if(!condition, &block)
|
79
71
|
end
|
80
|
-
alias_method :on_master_unless, :on_primary_unless
|
81
72
|
|
82
73
|
def on_primary_or_replica(which, &block)
|
83
74
|
if block_given?
|
@@ -86,7 +77,6 @@ module ActiveRecordShards
|
|
86
77
|
PrimaryReplicaProxy.new(self, which)
|
87
78
|
end
|
88
79
|
end
|
89
|
-
alias_method :on_master_or_slave, :on_primary_or_replica
|
90
80
|
|
91
81
|
# Executes queries using the replica database. Fails over to primary if no replica is found.
|
92
82
|
# if you want to execute a block of code on the replica you can go:
|
@@ -100,23 +90,14 @@ module ActiveRecordShards
|
|
100
90
|
def on_replica(&block)
|
101
91
|
on_primary_or_replica(:replica, &block)
|
102
92
|
end
|
103
|
-
alias_method :on_slave, :on_replica
|
104
93
|
|
105
94
|
def on_primary(&block)
|
106
95
|
on_primary_or_replica(:primary, &block)
|
107
96
|
end
|
108
|
-
alias_method :on_master, :on_primary
|
109
|
-
|
110
|
-
# just to ease the transition from replica to active_record_shards
|
111
|
-
alias_method :with_slave, :on_replica
|
112
|
-
alias_method :with_slave_if, :on_replica_if
|
113
|
-
alias_method :with_slave_unless, :on_replica_unless
|
114
97
|
|
115
98
|
def on_cx_switch_block(which, force: false, construct_ro_scope: nil, &block)
|
116
99
|
@disallow_replica ||= 0
|
117
|
-
@disallow_replica += 1 if
|
118
|
-
|
119
|
-
ActiveRecordShards::Deprecation.warn('the `:master` option should be replaced with `:primary`!') if which == :master
|
100
|
+
@disallow_replica += 1 if which == :primary
|
120
101
|
|
121
102
|
switch_to_replica = force || @disallow_replica.zero?
|
122
103
|
old_options = current_shard_selection.options
|
@@ -125,13 +106,13 @@ module ActiveRecordShards
|
|
125
106
|
|
126
107
|
# we avoid_readonly_scope to prevent some stack overflow problems, like when
|
127
108
|
# .columns calls .with_scope which calls .columns and onward, endlessly.
|
128
|
-
if self == ActiveRecord::Base || !switch_to_replica || construct_ro_scope == false
|
109
|
+
if self == ActiveRecord::Base || !switch_to_replica || construct_ro_scope == false || ActiveRecordShards.disable_replica_readonly_records == true
|
129
110
|
yield
|
130
111
|
else
|
131
112
|
readonly.scoping(&block)
|
132
113
|
end
|
133
114
|
ensure
|
134
|
-
@disallow_replica -= 1 if
|
115
|
+
@disallow_replica -= 1 if which == :primary
|
135
116
|
switch_connection(old_options) if old_options
|
136
117
|
end
|
137
118
|
|
@@ -142,7 +123,6 @@ module ActiveRecordShards
|
|
142
123
|
def on_replica?
|
143
124
|
current_shard_selection.on_replica?
|
144
125
|
end
|
145
|
-
alias_method :on_slave?, :on_replica?
|
146
126
|
|
147
127
|
def current_shard_selection
|
148
128
|
Thread.current[:shard_selection] ||= ShardSelection.new
|
@@ -153,18 +133,27 @@ module ActiveRecordShards
|
|
153
133
|
end
|
154
134
|
|
155
135
|
def shard_names
|
156
|
-
unless
|
157
|
-
raise "
|
158
|
-
end
|
159
|
-
unless config.fetch(SHARD_NAMES_CONFIG_KEY, []).all? { |shard_name| shard_name.is_a?(Integer) }
|
160
|
-
raise "All shard names must be integers: #{config[SHARD_NAMES_CONFIG_KEY].inspect}."
|
136
|
+
unless config_for_env.fetch(SHARD_NAMES_CONFIG_KEY, []).all? { |shard_name| shard_name.is_a?(Integer) }
|
137
|
+
raise "All shard names must be integers: #{config_for_env[SHARD_NAMES_CONFIG_KEY].inspect}."
|
161
138
|
end
|
162
139
|
|
163
|
-
|
140
|
+
config_for_env[SHARD_NAMES_CONFIG_KEY] || []
|
164
141
|
end
|
165
142
|
|
166
143
|
private
|
167
144
|
|
145
|
+
def config_for_env
|
146
|
+
@_ars_config_for_env ||= {}
|
147
|
+
@_ars_config_for_env[shard_env] ||= begin
|
148
|
+
unless config = configurations[shard_env]
|
149
|
+
raise "Did not find #{shard_env} in configurations, did you forget to add it to your database config? (configurations: #{configurations.to_h.keys.inspect})"
|
150
|
+
end
|
151
|
+
|
152
|
+
config
|
153
|
+
end
|
154
|
+
end
|
155
|
+
alias_method :check_config_for_env, :config_for_env
|
156
|
+
|
168
157
|
def switch_connection(options)
|
169
158
|
if options.any?
|
170
159
|
if options.key?(:replica)
|
@@ -172,9 +161,7 @@ module ActiveRecordShards
|
|
172
161
|
end
|
173
162
|
|
174
163
|
if options.key?(:shard)
|
175
|
-
|
176
|
-
raise "Did not find #{shard_env} in configurations, did you forget to add it to your database config? (configurations: #{configurations.keys.inspect})"
|
177
|
-
end
|
164
|
+
check_config_for_env
|
178
165
|
|
179
166
|
current_shard_selection.shard = options[:shard]
|
180
167
|
end
|
@@ -184,7 +171,7 @@ module ActiveRecordShards
|
|
184
171
|
end
|
185
172
|
|
186
173
|
def shard_env
|
187
|
-
ActiveRecordShards.
|
174
|
+
ActiveRecordShards.app_env
|
188
175
|
end
|
189
176
|
|
190
177
|
# Make these few schema related methods available before having switched to
|
@@ -197,14 +184,8 @@ module ActiveRecordShards
|
|
197
184
|
end
|
198
185
|
end
|
199
186
|
|
200
|
-
|
201
|
-
|
202
|
-
with_default_shard { load_schema_without_default_shard! }
|
203
|
-
end
|
204
|
-
else
|
205
|
-
def columns_with_default_shard
|
206
|
-
with_default_shard { columns_without_default_shard }
|
207
|
-
end
|
187
|
+
def load_schema_with_default_shard!
|
188
|
+
with_default_shard { load_schema_without_default_shard! }
|
208
189
|
end
|
209
190
|
|
210
191
|
def table_exists_with_default_shard?
|
@@ -220,19 +201,16 @@ module ActiveRecordShards
|
|
220
201
|
def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
221
202
|
@target.on_primary_or_replica(@which) { @target.send(method, *args, &block) }
|
222
203
|
end
|
204
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
223
205
|
end
|
224
|
-
|
225
|
-
MasterSlaveProxy = PrimaryReplicaProxy
|
226
206
|
end
|
227
207
|
end
|
228
208
|
|
229
209
|
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
230
|
-
when '
|
231
|
-
require 'active_record_shards/connection_switcher-4-2'
|
232
|
-
when '5.0'
|
233
|
-
require 'active_record_shards/connection_switcher-5-0'
|
234
|
-
when '5.1', '5.2', '6.0'
|
210
|
+
when '5.1', '5.2'
|
235
211
|
require 'active_record_shards/connection_switcher-5-1'
|
212
|
+
when '6.0'
|
213
|
+
require 'active_record_shards/connection_switcher-6-0'
|
236
214
|
else
|
237
215
|
raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
|
238
216
|
end
|
@@ -22,21 +22,13 @@ module ActiveRecordShards
|
|
22
22
|
#{method}_without_default_replica#{punctuation}(*args, &block)
|
23
23
|
end
|
24
24
|
end
|
25
|
-
|
25
|
+
ruby2_keywords(:#{method}_with_default_replica#{punctuation}) if respond_to?(:ruby2_keywords, true)
|
26
26
|
alias_method :#{method}_without_default_replica#{punctuation}, :#{method}#{punctuation}
|
27
27
|
alias_method :#{method}#{punctuation}, :#{method}_with_default_replica#{punctuation}
|
28
28
|
#{class_method ? 'end' : ''}
|
29
29
|
RUBY
|
30
30
|
end
|
31
31
|
|
32
|
-
def self.wrap_method_in_on_slave(*args)
|
33
|
-
ActiveRecordShards::Deprecation.deprecation_warning(
|
34
|
-
:'self.wrap_method_in_on_slave',
|
35
|
-
:'self.wrap_method_in_on_replica'
|
36
|
-
)
|
37
|
-
wrap_method_in_on_replica(*args)
|
38
|
-
end
|
39
|
-
|
40
32
|
def transaction_with_replica_off(*args, &block)
|
41
33
|
if on_replica_by_default?
|
42
34
|
begin
|
@@ -50,14 +42,9 @@ module ActiveRecordShards
|
|
50
42
|
transaction_without_replica_off(*args, &block)
|
51
43
|
end
|
52
44
|
end
|
53
|
-
|
45
|
+
ruby2_keywords(:transaction_with_replica_off) if respond_to?(:ruby2_keywords, true)
|
54
46
|
|
55
47
|
module InstanceMethods
|
56
|
-
# fix ActiveRecord to do the right thing, and use our aliased quote_value
|
57
|
-
def quote_value(*args, &block)
|
58
|
-
self.class.quote_value(*args, &block)
|
59
|
-
end
|
60
|
-
|
61
48
|
def on_replica_unless_tx
|
62
49
|
self.class.on_replica_unless_tx { yield }
|
63
50
|
end
|
@@ -84,19 +71,11 @@ module ActiveRecordShards
|
|
84
71
|
:table_exists?
|
85
72
|
].freeze
|
86
73
|
|
87
|
-
CLASS_SLAVE_METHODS = CLASS_REPLICA_METHODS
|
88
|
-
CLASS_FORCE_SLAVE_METHODS = CLASS_FORCE_REPLICA_METHODS
|
89
|
-
|
90
74
|
def self.extended(base)
|
91
75
|
CLASS_REPLICA_METHODS.each { |m| ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, m) }
|
92
76
|
CLASS_FORCE_REPLICA_METHODS.each { |m| ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, m, force_on_replica: true) }
|
93
77
|
|
94
|
-
|
95
|
-
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, :load_schema!, force_on_replica: true)
|
96
|
-
else
|
97
|
-
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, :columns, force_on_replica: true)
|
98
|
-
end
|
99
|
-
|
78
|
+
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(true, base, :load_schema!, force_on_replica: true)
|
100
79
|
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :reload)
|
101
80
|
|
102
81
|
base.class_eval do
|
@@ -119,7 +98,6 @@ module ActiveRecordShards
|
|
119
98
|
yield
|
120
99
|
end
|
121
100
|
end
|
122
|
-
alias_method :on_slave_unless_tx, :on_replica_unless_tx
|
123
101
|
|
124
102
|
def force_on_replica(&block)
|
125
103
|
return yield if Thread.current[:_active_record_shards_in_migration]
|
@@ -133,11 +111,6 @@ module ActiveRecordShards
|
|
133
111
|
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, m)
|
134
112
|
end
|
135
113
|
|
136
|
-
if ActiveRecord::VERSION::MAJOR == 4
|
137
|
-
# `where` and `having` clauses call `create_binds`, which will use the primary connection
|
138
|
-
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :create_binds, force_on_replica: true)
|
139
|
-
end
|
140
|
-
|
141
114
|
ActiveRecordShards::DefaultReplicaPatches.wrap_method_in_on_replica(false, base, :to_sql, force_on_replica: true)
|
142
115
|
end
|
143
116
|
|
@@ -210,20 +183,6 @@ module ActiveRecordShards
|
|
210
183
|
end
|
211
184
|
end
|
212
185
|
|
213
|
-
module AssociationsAssociationGetRecordsPatch
|
214
|
-
def get_records # rubocop:disable Naming/AccessorMethodName
|
215
|
-
if klass
|
216
|
-
on_replica_unless_tx { super }
|
217
|
-
else
|
218
|
-
super
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
|
-
def on_replica_unless_tx
|
223
|
-
klass.on_replica_unless_tx { yield }
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
186
|
module AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch
|
228
187
|
def associated_records_by_owner(preloader)
|
229
188
|
if klass
|
@@ -19,11 +19,10 @@ module ActiveRecord
|
|
19
19
|
# manually on the sharded DBs.
|
20
20
|
ActiveRecord::Base.on_all_shards do
|
21
21
|
ActiveRecord::SchemaMigration.create_table
|
22
|
-
|
23
|
-
ActiveRecord::InternalMetadata.create_table
|
24
|
-
end
|
22
|
+
ActiveRecord::InternalMetadata.create_table
|
25
23
|
end
|
26
24
|
end
|
25
|
+
ruby2_keywords(:initialize_with_sharding) if respond_to?(:ruby2_keywords, true)
|
27
26
|
alias_method :initialize_without_sharding, :initialize
|
28
27
|
alias_method :initialize, :initialize_with_sharding
|
29
28
|
|
@@ -34,7 +34,6 @@ module ActiveRecordShards
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
|
-
alias_method :on_slave_by_default?, :on_replica_by_default?
|
38
37
|
|
39
38
|
def on_replica_by_default=(value)
|
40
39
|
if self == ActiveRecord::Base
|
@@ -43,19 +42,16 @@ module ActiveRecordShards
|
|
43
42
|
base_class.instance_variable_set(:@on_replica_by_default, value)
|
44
43
|
end
|
45
44
|
end
|
46
|
-
alias_method :on_slave_by_default=, :on_replica_by_default=
|
47
45
|
|
48
46
|
module InstanceMethods
|
49
47
|
def initialize_shard_and_replica
|
50
48
|
@from_replica = !!self.class.current_shard_selection.options[:replica]
|
51
49
|
@from_shard = self.class.current_shard_selection.options[:shard]
|
52
50
|
end
|
53
|
-
alias_method :initialize_shard_and_slave, :initialize_shard_and_replica
|
54
51
|
|
55
52
|
def from_replica?
|
56
53
|
@from_replica
|
57
54
|
end
|
58
|
-
alias_method :from_slave?, :from_replica?
|
59
55
|
|
60
56
|
def from_shard
|
61
57
|
@from_shard
|
@@ -10,64 +10,33 @@ module ActiveRecordShards
|
|
10
10
|
@shard = nil
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
nil
|
19
|
-
else
|
20
|
-
@shard || self.class.default_shard
|
21
|
-
end
|
22
|
-
end
|
13
|
+
def shard
|
14
|
+
if @shard.nil? || @shard == NO_SHARD
|
15
|
+
nil
|
16
|
+
else
|
17
|
+
@shard || self.class.default_shard
|
23
18
|
end
|
19
|
+
end
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
else
|
41
|
-
|
42
|
-
def shard
|
43
|
-
if @shard.nil? || @shard == NO_SHARD
|
44
|
-
nil
|
21
|
+
PRIMARY = "primary"
|
22
|
+
def resolve_connection_name(sharded:, configurations:)
|
23
|
+
resolved_shard = sharded ? shard : nil
|
24
|
+
env = ActiveRecordShards.app_env
|
25
|
+
|
26
|
+
@connection_names ||= {}
|
27
|
+
@connection_names[env] ||= {}
|
28
|
+
@connection_names[env][resolved_shard] ||= {}
|
29
|
+
@connection_names[env][resolved_shard][@on_replica] ||= begin
|
30
|
+
name = env.dup
|
31
|
+
name << "_shard_#{resolved_shard}" if resolved_shard
|
32
|
+
if @on_replica && configurations["#{name}_replica"]
|
33
|
+
"#{name}_replica"
|
45
34
|
else
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
PRIMARY = "primary"
|
51
|
-
def resolve_connection_name(sharded:, configurations:)
|
52
|
-
resolved_shard = sharded ? shard : nil
|
53
|
-
env = ActiveRecordShards.rails_env
|
54
|
-
|
55
|
-
@connection_names ||= {}
|
56
|
-
@connection_names[env] ||= {}
|
57
|
-
@connection_names[env][resolved_shard] ||= {}
|
58
|
-
@connection_names[env][resolved_shard][@on_replica] ||= begin
|
59
|
-
name = env.dup
|
60
|
-
name << "_shard_#{resolved_shard}" if resolved_shard
|
61
|
-
if @on_replica && configurations["#{name}_replica"]
|
62
|
-
"#{name}_replica"
|
63
|
-
else
|
64
|
-
# ActiveRecord always names its default connection pool 'primary'
|
65
|
-
# while everything else is named by the configuration name
|
66
|
-
resolved_shard ? name : PRIMARY
|
67
|
-
end
|
35
|
+
# ActiveRecord always names its default connection pool 'primary'
|
36
|
+
# while everything else is named by the configuration name
|
37
|
+
resolved_shard ? name : PRIMARY
|
68
38
|
end
|
69
39
|
end
|
70
|
-
|
71
40
|
end
|
72
41
|
|
73
42
|
def shard=(new_shard)
|
@@ -77,12 +46,10 @@ module ActiveRecordShards
|
|
77
46
|
def on_replica?
|
78
47
|
@on_replica
|
79
48
|
end
|
80
|
-
alias_method :on_slave?, :on_replica?
|
81
49
|
|
82
50
|
def on_replica=(new_replica)
|
83
51
|
@on_replica = (new_replica == true)
|
84
52
|
end
|
85
|
-
alias_method :on_slave=, :on_replica=
|
86
53
|
|
87
54
|
def options
|
88
55
|
{ shard: @shard, replica: @on_replica }
|
@@ -23,15 +23,14 @@ module ActiveRecordShards
|
|
23
23
|
|
24
24
|
exception = nil
|
25
25
|
enum.each do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
exception = e
|
31
|
-
end
|
26
|
+
record = @scope.find(*find_args)
|
27
|
+
return record if record
|
28
|
+
rescue ActiveRecord::RecordNotFound => e
|
29
|
+
exception = e
|
32
30
|
end
|
33
31
|
raise exception
|
34
32
|
end
|
33
|
+
ruby2_keywords(:find) if respond_to?(:ruby2_keywords, true)
|
35
34
|
|
36
35
|
def count
|
37
36
|
enum.inject(0) { |accum, _shard| @scope.clone.count + accum }
|
@@ -10,7 +10,7 @@ namespace :db do
|
|
10
10
|
desc 'Drops the database for the current RAILS_ENV including shards'
|
11
11
|
task drop: :load_config do
|
12
12
|
ActiveRecord::Base.configurations.to_h.each do |key, conf|
|
13
|
-
next if !key.start_with?(ActiveRecordShards.
|
13
|
+
next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
|
14
14
|
|
15
15
|
begin
|
16
16
|
ActiveRecordShards::Tasks.root_connection(conf).drop_database(conf['database'])
|
@@ -31,7 +31,7 @@ namespace :db do
|
|
31
31
|
desc "Create the database defined in config/database.yml for the current RAILS_ENV including shards"
|
32
32
|
task create: :load_config do
|
33
33
|
ActiveRecord::Base.configurations.to_h.each do |key, conf|
|
34
|
-
next if !key.start_with?(ActiveRecordShards.
|
34
|
+
next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
|
35
35
|
|
36
36
|
begin
|
37
37
|
# MysqlAdapter takes charset instead of encoding in Rails 4.2 or greater
|
@@ -48,7 +48,7 @@ namespace :db do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
51
|
-
ActiveRecord::Base.establish_connection(ActiveRecordShards.
|
51
|
+
ActiveRecord::Base.establish_connection(ActiveRecordShards.app_env.to_sym)
|
52
52
|
end
|
53
53
|
|
54
54
|
desc "Raises an error if there are pending migrations"
|
@@ -78,14 +78,12 @@ namespace :db do
|
|
78
78
|
namespace :test do
|
79
79
|
desc 'Purges the test databases by dropping and creating'
|
80
80
|
task purge: :load_config do |t|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
Rails.env = saved_env
|
88
|
-
end
|
81
|
+
saved_env = Rails.env
|
82
|
+
Rails.env = 'test'
|
83
|
+
Rake.application.lookup('db:drop', t.scope).execute
|
84
|
+
Rake.application.lookup('db:create', t.scope).execute
|
85
|
+
ensure
|
86
|
+
Rails.env = saved_env
|
89
87
|
end
|
90
88
|
end
|
91
89
|
end
|
data/lib/active_record_shards.rb
CHANGED
@@ -12,10 +12,16 @@ require 'active_record_shards/default_replica_patches'
|
|
12
12
|
require 'active_record_shards/schema_dumper_extension'
|
13
13
|
|
14
14
|
module ActiveRecordShards
|
15
|
-
|
15
|
+
class << self
|
16
|
+
attr_accessor :disable_replica_readonly_records
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.app_env
|
16
20
|
env = Rails.env if defined?(Rails.env)
|
17
21
|
env ||= RAILS_ENV if Object.const_defined?(:RAILS_ENV)
|
18
22
|
env ||= ENV['RAILS_ENV']
|
23
|
+
env ||= APP_ENV if Object.const_defined?(:APP_ENV)
|
24
|
+
env ||= ENV['APP_ENV']
|
19
25
|
env || 'development'
|
20
26
|
end
|
21
27
|
end
|
@@ -30,32 +36,6 @@ ActiveRecord::Associations::Builder::HasAndBelongsToMany.include(ActiveRecordSha
|
|
30
36
|
ActiveRecord::SchemaDumper.prepend(ActiveRecordShards::SchemaDumperExtension)
|
31
37
|
|
32
38
|
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
33
|
-
when '4.2'
|
34
|
-
require 'active_record_shards/patches-4-2'
|
35
|
-
|
36
|
-
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/association.rb#L97
|
37
|
-
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
38
|
-
|
39
|
-
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/singular_association.rb#L44-L53
|
40
|
-
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
41
|
-
|
42
|
-
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/collection_association.rb#L447-L456
|
43
|
-
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
44
|
-
|
45
|
-
# https://github.com/rails/rails/blob/v4.2.11.3/activerecord/lib/active_record/associations/preloader/association.rb#L89
|
46
|
-
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationAssociatedRecordsByOwnerPatch)
|
47
|
-
when '5.0'
|
48
|
-
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/association.rb#L97
|
49
|
-
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
50
|
-
|
51
|
-
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/singular_association.rb#L56-L65
|
52
|
-
ActiveRecord::Associations::SingularAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
53
|
-
|
54
|
-
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/collection_association.rb#L442-L451
|
55
|
-
ActiveRecord::Associations::CollectionAssociation.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationGetRecordsPatch)
|
56
|
-
|
57
|
-
# https://github.com/rails/rails/blob/v5.0.7/activerecord/lib/active_record/associations/preloader/association.rb#L120
|
58
|
-
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
59
39
|
when '5.1'
|
60
40
|
# https://github.com/rails/rails/blob/v5.1.7/activerecord/lib/active_record/associations/association.rb#L97
|
61
41
|
ActiveRecord::Associations::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsAssociationAssociationScopePatch)
|
@@ -97,45 +77,3 @@ when '6.0'
|
|
97
77
|
else
|
98
78
|
raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
|
99
79
|
end
|
100
|
-
|
101
|
-
require 'active_record_shards/deprecation'
|
102
|
-
|
103
|
-
ActiveRecordShards::Deprecation.deprecate_methods(
|
104
|
-
ActiveRecordShards::AssociationCollectionConnectionSelection,
|
105
|
-
on_slave_if: :on_replica_if,
|
106
|
-
on_slave_unless: :on_replica_unless,
|
107
|
-
on_slave: :on_replica,
|
108
|
-
on_master: :on_primary,
|
109
|
-
on_master_if: :on_primary_if,
|
110
|
-
on_master_unless: :on_primary_unless
|
111
|
-
)
|
112
|
-
|
113
|
-
ActiveRecordShards::Deprecation.deprecate_methods(
|
114
|
-
ActiveRecordShards::ConnectionSwitcher,
|
115
|
-
on_slave_if: :on_replica_if,
|
116
|
-
on_slave_unless: :on_replica_unless,
|
117
|
-
on_master_or_slave: :on_primary_or_replica,
|
118
|
-
on_slave: :on_replica,
|
119
|
-
on_master: :on_primary,
|
120
|
-
on_master_if: :on_primary_if,
|
121
|
-
on_master_unless: :on_primary_unless,
|
122
|
-
on_slave?: :on_replica?
|
123
|
-
)
|
124
|
-
|
125
|
-
ActiveRecordShards::Deprecation.deprecate_methods(
|
126
|
-
ActiveRecordShards::DefaultReplicaPatches,
|
127
|
-
transaction_with_slave_off: :transaction_with_replica_off,
|
128
|
-
on_slave_unless_tx: :on_replica_unless_tx
|
129
|
-
)
|
130
|
-
|
131
|
-
ActiveRecordShards::Deprecation.deprecate_methods(
|
132
|
-
ActiveRecordShards::Model,
|
133
|
-
on_slave_by_default?: :on_replica_by_default?,
|
134
|
-
:on_slave_by_default= => :on_replica_by_default=
|
135
|
-
)
|
136
|
-
|
137
|
-
ActiveRecordShards::Deprecation.deprecate_methods(
|
138
|
-
ActiveRecordShards::ShardSelection,
|
139
|
-
on_slave?: :on_replica?,
|
140
|
-
:on_slave= => :on_replica=
|
141
|
-
)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_shards
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Quorning
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date:
|
16
|
+
date: 2022-07-06 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: activerecord
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
requirements:
|
22
22
|
- - ">="
|
23
23
|
- !ruby/object:Gem::Version
|
24
|
-
version: '
|
24
|
+
version: '5.1'
|
25
25
|
- - "<"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '6.1'
|
@@ -31,7 +31,7 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
34
|
+
version: '5.1'
|
35
35
|
- - "<"
|
36
36
|
- !ruby/object:Gem::Version
|
37
37
|
version: '6.1'
|
@@ -41,7 +41,7 @@ dependencies:
|
|
41
41
|
requirements:
|
42
42
|
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version: '
|
44
|
+
version: '5.1'
|
45
45
|
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '6.1'
|
@@ -51,7 +51,7 @@ dependencies:
|
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '5.1'
|
55
55
|
- - "<"
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '6.1'
|
@@ -195,19 +195,12 @@ files:
|
|
195
195
|
- lib/active_record_shards.rb
|
196
196
|
- lib/active_record_shards/association_collection_connection_selection.rb
|
197
197
|
- lib/active_record_shards/configuration_parser.rb
|
198
|
-
- lib/active_record_shards/connection_handler.rb
|
199
|
-
- lib/active_record_shards/connection_pool.rb
|
200
|
-
- lib/active_record_shards/connection_specification.rb
|
201
|
-
- lib/active_record_shards/connection_switcher-4-2.rb
|
202
|
-
- lib/active_record_shards/connection_switcher-5-0.rb
|
203
198
|
- lib/active_record_shards/connection_switcher-5-1.rb
|
199
|
+
- lib/active_record_shards/connection_switcher-6-0.rb
|
204
200
|
- lib/active_record_shards/connection_switcher.rb
|
205
201
|
- lib/active_record_shards/default_replica_patches.rb
|
206
|
-
- lib/active_record_shards/default_slave_patches.rb
|
207
|
-
- lib/active_record_shards/deprecation.rb
|
208
202
|
- lib/active_record_shards/migration.rb
|
209
203
|
- lib/active_record_shards/model.rb
|
210
|
-
- lib/active_record_shards/patches-4-2.rb
|
211
204
|
- lib/active_record_shards/schema_dumper_extension.rb
|
212
205
|
- lib/active_record_shards/shard_selection.rb
|
213
206
|
- lib/active_record_shards/shard_support.rb
|
@@ -225,14 +218,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
218
|
requirements:
|
226
219
|
- - ">="
|
227
220
|
- !ruby/object:Gem::Version
|
228
|
-
version: '2.
|
221
|
+
version: '2.6'
|
229
222
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
230
223
|
requirements:
|
231
224
|
- - ">="
|
232
225
|
- !ruby/object:Gem::Version
|
233
226
|
version: '0'
|
234
227
|
requirements: []
|
235
|
-
rubygems_version: 3.
|
228
|
+
rubygems_version: 3.1.6
|
236
229
|
signing_key:
|
237
230
|
specification_version: 4
|
238
231
|
summary: Simple database switching for ActiveRecord.
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveRecordShards
|
4
|
-
ConnectionPoolNameDecorator = Struct.new(:name)
|
5
|
-
|
6
|
-
# It overrides given connection handler methods (they differ depend on
|
7
|
-
# Rails version).
|
8
|
-
#
|
9
|
-
# It takes the first argument, ActiveRecord::Base object or
|
10
|
-
# String (connection_pool_name), converts it in Struct object and
|
11
|
-
# passes to the original method.
|
12
|
-
#
|
13
|
-
# Example:
|
14
|
-
# methods_to_override = [:establish_connection, :remove_connection]
|
15
|
-
# ActiveRecordShards.override_connection_handler_methods(methods_to_override)
|
16
|
-
#
|
17
|
-
def self.override_connection_handler_methods(method_names)
|
18
|
-
method_names.each do |method_name|
|
19
|
-
ActiveRecord::ConnectionAdapters::ConnectionHandler.class_eval do
|
20
|
-
define_method("#{method_name}_with_connection_pool_name") do |*args|
|
21
|
-
unless args[0].is_a? ConnectionPoolNameDecorator
|
22
|
-
name = if args[0].is_a? String
|
23
|
-
args[0]
|
24
|
-
else
|
25
|
-
args[0].connection_pool_name
|
26
|
-
end
|
27
|
-
args[0] = ConnectionPoolNameDecorator.new(name)
|
28
|
-
end
|
29
|
-
send("#{method_name}_without_connection_pool_name", *args)
|
30
|
-
end
|
31
|
-
alias_method :"#{method_name}_without_connection_pool_name", method_name
|
32
|
-
alias_method method_name, :"#{method_name}_with_connection_pool_name"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class << ActiveRecord::Base
|
4
|
-
remove_method :establish_connection if ActiveRecord::VERSION::MAJOR >= 5
|
5
|
-
def establish_connection(spec = ENV["DATABASE_URL"])
|
6
|
-
spec ||= ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
|
7
|
-
spec = spec.to_sym if spec.is_a?(String)
|
8
|
-
resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
|
9
|
-
spec = resolver.spec(spec)
|
10
|
-
|
11
|
-
unless respond_to?(spec.adapter_method)
|
12
|
-
raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter"
|
13
|
-
end
|
14
|
-
|
15
|
-
remove_connection
|
16
|
-
specification_cache[connection_pool_name] = spec
|
17
|
-
connection_handler.establish_connection self, spec
|
18
|
-
end
|
19
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module ActiveRecordShards
|
2
|
-
module ConnectionSwitcher
|
3
|
-
# Name of the connection pool. Used by ConnectionHandler to retrieve the current connection pool.
|
4
|
-
def connection_pool_name # :nodoc:
|
5
|
-
name = current_shard_selection.shard_name(self)
|
6
|
-
|
7
|
-
# e.g. if "production_replica" is not defined in `Configuration`, fall back to "production"
|
8
|
-
if configurations[name].nil? && on_replica?
|
9
|
-
current_shard_selection.shard_name(self, false)
|
10
|
-
else
|
11
|
-
name
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def ensure_shard_connection
|
18
|
-
establish_shard_connection unless connected_to_shard?
|
19
|
-
end
|
20
|
-
|
21
|
-
def establish_shard_connection
|
22
|
-
name = connection_pool_name
|
23
|
-
spec = configurations[name]
|
24
|
-
|
25
|
-
if spec.nil?
|
26
|
-
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.keys.inspect})"
|
27
|
-
end
|
28
|
-
|
29
|
-
specification_cache[name] ||= begin
|
30
|
-
resolver = ActiveRecordShards::ConnectionSpecification::Resolver.new configurations
|
31
|
-
resolver.spec(spec)
|
32
|
-
end
|
33
|
-
|
34
|
-
connection_handler.establish_connection(self, specification_cache[name])
|
35
|
-
end
|
36
|
-
|
37
|
-
def specification_cache
|
38
|
-
@@specification_cache ||= {}
|
39
|
-
end
|
40
|
-
|
41
|
-
# Helper method to clear global state when testing.
|
42
|
-
def clear_specification_cache
|
43
|
-
@@specification_cache = {}
|
44
|
-
end
|
45
|
-
|
46
|
-
def connection_pool_key
|
47
|
-
specification_cache[connection_pool_name]
|
48
|
-
end
|
49
|
-
|
50
|
-
def connected_to_shard?
|
51
|
-
specs_to_pools = Hash[connection_handler.connection_pool_list.map { |pool| [pool.spec, pool] }]
|
52
|
-
|
53
|
-
specs_to_pools.key?(connection_pool_key)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module ActiveRecordShards
|
2
|
-
class Deprecation < ActiveSupport::Deprecation
|
3
|
-
# This allows us to define separate deprecation behavior for ActiveRecordShards, but defaults to
|
4
|
-
# the same behavior globally configured with ActiveSupport.
|
5
|
-
#
|
6
|
-
# For example, this allows us to silence our own deprecation warnings in test while still being
|
7
|
-
# able to fail tests for upstream deprecation warnings.
|
8
|
-
def behavior
|
9
|
-
@behavior ||= ActiveSupport::Deprecation.behavior
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,9 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'active_record_shards/connection_pool'
|
4
|
-
require 'active_record_shards/connection_handler'
|
5
|
-
require 'active_record_shards/connection_specification'
|
6
|
-
|
7
|
-
ActiveRecordShards::ConnectionSpecification = ActiveRecord::ConnectionAdapters::ConnectionSpecification
|
8
|
-
methods_to_override = [:establish_connection, :remove_connection, :pool_for, :pool_from_any_process_for]
|
9
|
-
ActiveRecordShards.override_connection_handler_methods(methods_to_override)
|