active_record_shards 5.0.0 → 5.2.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 +18 -0
- data/lib/active_record_shards/connection_switcher-6-1.rb +31 -0
- data/lib/active_record_shards/connection_switcher-7-0.rb +31 -0
- data/lib/active_record_shards/connection_switcher.rb +19 -7
- data/lib/active_record_shards/default_shard.rb +27 -0
- data/lib/active_record_shards/shard_selection.rb +19 -5
- data/lib/active_record_shards/tasks.rb +44 -6
- data/lib/active_record_shards.rb +2 -1
- metadata +13 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15b0d33ae1fec065fc2c2763f52bf5385da900ddbc3d8b55089ac6f1f99f9b1c
|
4
|
+
data.tar.gz: 61de1ca1ad18611d9eb059dcec55eb85e4de55c965dd3ee33c60088a5d68f4f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90e52914b1a63fbfb633882f60f2c2020a057b7ad16530c5800cc44f2e88d551c638fcdc31615f2c1c13d4fd031148ce568a10d4776c0082b0c917e9c7ee8dba
|
7
|
+
data.tar.gz: 8b215a24c9c0e1ff79e75499b9d47976b0143095023c0ec2a1ab4c03cc5e9c048957ef63703fe2a8eef5b92c72b3d156a95662ac3367a67ec6324f9527142913
|
data/README.md
CHANGED
@@ -7,6 +7,8 @@ switch between database connections. We've made the implementation very small, a
|
|
7
7
|
|
8
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
|
+
Rails 6.1 introduced new connection handling and support for sharding. Apps are encouraged to migrate to the native sharding logic but ActiveRecord Shards supports Rails 6.1 when `legacy_connection_handling` is set to `true`. For more information see [Rails 6.1 installation](#rails-61-installation) and Rails' [multiple databases guide](https://guides.rubyonrails.org/active_record_multiple_databases.html).
|
11
|
+
|
10
12
|
- [Installation](#installation)
|
11
13
|
- [Configuration](#configuration)
|
12
14
|
- [Migrations](#migrations)
|
@@ -22,6 +24,22 @@ ActiveRecord Shards has been used and tested on Rails 5.x and 6.0, and has in so
|
|
22
24
|
|
23
25
|
and make sure to require 'active\_record\_shards' in some way.
|
24
26
|
|
27
|
+
### Rails 6.1 & 7.0 installation
|
28
|
+
|
29
|
+
Rails 6.1 & 7.0 are **only** supported with `legacy_connection_handling` set to `true`.
|
30
|
+
|
31
|
+
Enable the legacy handling in your configuration files e.g. `config/application.rb` by setting:
|
32
|
+
|
33
|
+
``` Ruby
|
34
|
+
config.active_record.legacy_connection_handling = true
|
35
|
+
```
|
36
|
+
|
37
|
+
or
|
38
|
+
|
39
|
+
``` Ruby
|
40
|
+
ActiveRecord::Base.legacy_connection_handling = true
|
41
|
+
```
|
42
|
+
|
25
43
|
## Configuration
|
26
44
|
|
27
45
|
Add the replica and shard configuration to config/database.yml:
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveRecordShards
|
2
|
+
module ConnectionSwitcher
|
3
|
+
def connection_specification_name
|
4
|
+
name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
|
5
|
+
|
6
|
+
@_ars_connection_specification_names ||= {}
|
7
|
+
unless @_ars_connection_specification_names.include?(name)
|
8
|
+
unless configurations.configs_for(env_name: name, include_replicas: true).any? || name == "ActiveRecord::Base"
|
9
|
+
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.configurations.map(&:env_name).inspect})"
|
10
|
+
end
|
11
|
+
|
12
|
+
@_ars_connection_specification_names[name] = true
|
13
|
+
end
|
14
|
+
|
15
|
+
name
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def ensure_shard_connection
|
21
|
+
# See if we've connected before. If not, call `#establish_connection`
|
22
|
+
# so that ActiveRecord can resolve connection_specification_name to an
|
23
|
+
# ARS connection.
|
24
|
+
spec_name = connection_specification_name
|
25
|
+
|
26
|
+
pool = connection_handler.retrieve_connection_pool(spec_name)
|
27
|
+
|
28
|
+
connection_handler.establish_connection(spec_name.to_sym) if pool.nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ActiveRecordShards
|
2
|
+
module ConnectionSwitcher
|
3
|
+
def connection_specification_name
|
4
|
+
name = current_shard_selection.resolve_connection_name(sharded: is_sharded?, configurations: configurations)
|
5
|
+
|
6
|
+
@_ars_connection_specification_names ||= {}
|
7
|
+
unless @_ars_connection_specification_names.include?(name)
|
8
|
+
unless configurations.configs_for(env_name: name, include_hidden: true).any? || name == "ActiveRecord::Base"
|
9
|
+
raise ActiveRecord::AdapterNotSpecified, "No database defined by #{name} in your database config. (configurations: #{configurations.configurations.map(&:env_name).inspect})"
|
10
|
+
end
|
11
|
+
|
12
|
+
@_ars_connection_specification_names[name] = true
|
13
|
+
end
|
14
|
+
|
15
|
+
name
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def ensure_shard_connection
|
21
|
+
# See if we've connected before. If not, call `#establish_connection`
|
22
|
+
# so that ActiveRecord can resolve connection_specification_name to an
|
23
|
+
# ARS connection.
|
24
|
+
spec_name = connection_specification_name
|
25
|
+
|
26
|
+
pool = connection_handler.retrieve_connection_pool(spec_name)
|
27
|
+
|
28
|
+
connection_handler.establish_connection(spec_name.to_sym) if pool.nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -4,7 +4,12 @@ require 'active_record_shards/shard_support'
|
|
4
4
|
|
5
5
|
module ActiveRecordShards
|
6
6
|
module ConnectionSwitcher
|
7
|
-
|
7
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
8
|
+
when '6.1', '7.0'
|
9
|
+
SHARD_NAMES_CONFIG_KEY = :shard_names
|
10
|
+
else
|
11
|
+
SHARD_NAMES_CONFIG_KEY = 'shard_names'
|
12
|
+
end
|
8
13
|
|
9
14
|
def self.extended(base)
|
10
15
|
base.singleton_class.send(:alias_method, :load_schema_without_default_shard!, :load_schema!)
|
@@ -14,11 +19,6 @@ module ActiveRecordShards
|
|
14
19
|
base.singleton_class.send(:alias_method, :table_exists?, :table_exists_with_default_shard?)
|
15
20
|
end
|
16
21
|
|
17
|
-
def default_shard=(new_default_shard)
|
18
|
-
ActiveRecordShards::ShardSelection.default_shard = new_default_shard
|
19
|
-
switch_connection(shard: new_default_shard)
|
20
|
-
end
|
21
|
-
|
22
22
|
def on_primary_db(&block)
|
23
23
|
on_shard(nil, &block)
|
24
24
|
end
|
@@ -145,7 +145,15 @@ module ActiveRecordShards
|
|
145
145
|
def config_for_env
|
146
146
|
@_ars_config_for_env ||= {}
|
147
147
|
@_ars_config_for_env[shard_env] ||= begin
|
148
|
-
|
148
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
149
|
+
when '7.0'
|
150
|
+
config = configurations.configs_for(env_name: shard_env, include_hidden: true).first.configuration_hash
|
151
|
+
when '6.1'
|
152
|
+
config = configurations.configs_for(env_name: shard_env, include_replicas: true).first.configuration_hash
|
153
|
+
else
|
154
|
+
config = configurations[shard_env]
|
155
|
+
end
|
156
|
+
unless config
|
149
157
|
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
158
|
end
|
151
159
|
|
@@ -211,6 +219,10 @@ when '5.1', '5.2'
|
|
211
219
|
require 'active_record_shards/connection_switcher-5-1'
|
212
220
|
when '6.0'
|
213
221
|
require 'active_record_shards/connection_switcher-6-0'
|
222
|
+
when '6.1'
|
223
|
+
require 'active_record_shards/connection_switcher-6-1'
|
224
|
+
when '7.0'
|
225
|
+
require 'active_record_shards/connection_switcher-7-0'
|
214
226
|
else
|
215
227
|
raise "ActiveRecordShards is not compatible with #{ActiveRecord::VERSION::STRING}"
|
216
228
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordShards
|
4
|
+
module DefaultShard
|
5
|
+
def default_shard=(new_default_shard)
|
6
|
+
if ars_shard_type?(new_default_shard)
|
7
|
+
ActiveRecordShards::ShardSelection.ars_default_shard = new_default_shard
|
8
|
+
switch_connection(shard: new_default_shard)
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def ars_shard_type?(shard)
|
17
|
+
return true if ActiveRecord.version < Gem::Version.new('6.1')
|
18
|
+
return true if shard.nil?
|
19
|
+
return true if shard == :_no_shard
|
20
|
+
return true if shard.is_a?(Integer)
|
21
|
+
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
ActiveRecord::Base.singleton_class.prepend(ActiveRecordShards::DefaultShard)
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module ActiveRecordShards
|
4
4
|
class ShardSelection
|
5
5
|
NO_SHARD = :_no_shard
|
6
|
-
cattr_accessor :
|
6
|
+
cattr_accessor :ars_default_shard
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
@on_replica = false
|
@@ -14,11 +14,15 @@ module ActiveRecordShards
|
|
14
14
|
if @shard.nil? || @shard == NO_SHARD
|
15
15
|
nil
|
16
16
|
else
|
17
|
-
@shard || self.class.
|
17
|
+
@shard || self.class.ars_default_shard
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
21
|
-
|
20
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
21
|
+
when '6.1', '7.0'
|
22
|
+
PRIMARY = "ActiveRecord::Base"
|
23
|
+
else
|
24
|
+
PRIMARY = "primary"
|
25
|
+
end
|
22
26
|
def resolve_connection_name(sharded:, configurations:)
|
23
27
|
resolved_shard = sharded ? shard : nil
|
24
28
|
env = ActiveRecordShards.app_env
|
@@ -29,7 +33,17 @@ module ActiveRecordShards
|
|
29
33
|
@connection_names[env][resolved_shard][@on_replica] ||= begin
|
30
34
|
name = env.dup
|
31
35
|
name << "_shard_#{resolved_shard}" if resolved_shard
|
32
|
-
|
36
|
+
replica_config = begin
|
37
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
38
|
+
when '7.0'
|
39
|
+
configurations.configs_for(env_name: "#{name}_replica", include_hidden: true).any?
|
40
|
+
when '6.1'
|
41
|
+
configurations.configs_for(env_name: "#{name}_replica", include_replicas: true).any?
|
42
|
+
else
|
43
|
+
configurations["#{name}_replica"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if @on_replica && replica_config
|
33
47
|
"#{name}_replica"
|
34
48
|
else
|
35
49
|
# ActiveRecord always names its default connection pool 'primary'
|
@@ -9,10 +9,24 @@ end
|
|
9
9
|
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
|
+
configurations = begin
|
13
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
14
|
+
when '6.1', '7.0'
|
15
|
+
ActiveRecord::Base.configurations.configurations.map { |configuration| [configuration.env_name, configuration.configuration_hash] }
|
16
|
+
else
|
17
|
+
ActiveRecord::Base.configurations.to_h
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
configurations.each do |key, conf|
|
13
22
|
next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
|
14
23
|
|
15
24
|
begin
|
25
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
26
|
+
when '6.1', '7.0'
|
27
|
+
conf = conf.stringify_keys
|
28
|
+
end
|
29
|
+
|
16
30
|
ActiveRecordShards::Tasks.root_connection(conf).drop_database(conf['database'])
|
17
31
|
# rescue ActiveRecord::NoDatabaseError # TODO: exists in AR but never is raised here ...
|
18
32
|
# $stderr.puts "Database '#{conf['database']}' does not exist"
|
@@ -30,13 +44,26 @@ namespace :db do
|
|
30
44
|
|
31
45
|
desc "Create the database defined in config/database.yml for the current RAILS_ENV including shards"
|
32
46
|
task create: :load_config do
|
33
|
-
|
47
|
+
configurations = begin
|
48
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
49
|
+
when '6.1', '7.0'
|
50
|
+
ActiveRecord::Base.configurations.configurations.map { |configuration| [configuration.env_name, configuration.configuration_hash] }
|
51
|
+
else
|
52
|
+
ActiveRecord::Base.configurations.to_h
|
53
|
+
end
|
54
|
+
end
|
55
|
+
configurations.each do |key, conf|
|
34
56
|
next if !key.start_with?(ActiveRecordShards.app_env) || key.end_with?("_replica")
|
35
57
|
|
36
58
|
begin
|
37
59
|
# MysqlAdapter takes charset instead of encoding in Rails 4.2 or greater
|
38
60
|
# https://github.com/rails/rails/blob/4-2-stable/activerecord/lib/active_record/tasks/mysql_database_tasks.rb#L85-L96
|
39
61
|
symbolized_configuration = conf.symbolize_keys
|
62
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
63
|
+
when '6.1', '7.0'
|
64
|
+
conf = conf.stringify_keys
|
65
|
+
end
|
66
|
+
|
40
67
|
symbolized_configuration[:charset] = symbolized_configuration[:encoding]
|
41
68
|
|
42
69
|
ActiveRecordShards::Tasks.root_connection(conf).create_database(conf['database'], symbolized_configuration)
|
@@ -94,15 +121,26 @@ module ActiveRecordShards
|
|
94
121
|
def root_connection(conf)
|
95
122
|
conf = conf.merge('database' => nil)
|
96
123
|
spec = spec_for(conf)
|
97
|
-
|
98
|
-
|
124
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
125
|
+
when '6.1', '7.0'
|
126
|
+
ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.db_config.configuration_hash)
|
127
|
+
else
|
128
|
+
ActiveRecord::Base.send("#{conf['adapter']}_connection", spec.config)
|
129
|
+
end
|
99
130
|
end
|
100
131
|
|
101
132
|
private
|
102
133
|
|
103
134
|
def spec_for(conf)
|
104
|
-
|
105
|
-
|
135
|
+
case "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}"
|
136
|
+
when '7.0'
|
137
|
+
ActiveRecord::Base.connection_handler.send(:resolve_pool_config, conf, ActiveRecord::Base, ActiveRecord::Base.current_role, ActiveRecord::Base.current_shard)
|
138
|
+
when '6.1'
|
139
|
+
ActiveRecord::Base.connection_handler.send(:resolve_pool_config, conf, ActiveRecord::Base)
|
140
|
+
else
|
141
|
+
resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(ActiveRecord::Base.configurations)
|
142
|
+
resolver.spec(conf)
|
143
|
+
end
|
106
144
|
end
|
107
145
|
end
|
108
146
|
end
|
data/lib/active_record_shards.rb
CHANGED
@@ -9,6 +9,7 @@ require 'active_record_shards/connection_switcher'
|
|
9
9
|
require 'active_record_shards/association_collection_connection_selection'
|
10
10
|
require 'active_record_shards/migration'
|
11
11
|
require 'active_record_shards/default_replica_patches'
|
12
|
+
require 'active_record_shards/default_shard'
|
12
13
|
require 'active_record_shards/schema_dumper_extension'
|
13
14
|
|
14
15
|
module ActiveRecordShards
|
@@ -61,7 +62,7 @@ when '5.2'
|
|
61
62
|
|
62
63
|
# https://github.com/rails/rails/blob/v5.2.6/activerecord/lib/active_record/associations/preloader/association.rb#L96
|
63
64
|
ActiveRecord::Associations::Preloader::Association.prepend(ActiveRecordShards::DefaultReplicaPatches::AssociationsPreloaderAssociationLoadRecordsPatch)
|
64
|
-
when '6.0'
|
65
|
+
when '6.0', '6.1', '7.0'
|
65
66
|
# https://github.com/rails/rails/blob/v6.0.4/activerecord/lib/active_record/type_caster/connection.rb#L28
|
66
67
|
ActiveRecord::TypeCaster::Connection.prepend(ActiveRecordShards::DefaultReplicaPatches::TypeCasterConnectionConnectionPatch)
|
67
68
|
|
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: 5.
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Quorning
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
- Mick Staugaard
|
11
11
|
- Eric Chapweske
|
12
12
|
- Ben Osheroff
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2022-
|
16
|
+
date: 2022-10-11 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: activerecord
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
version: '5.1'
|
25
25
|
- - "<"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '7.1'
|
28
28
|
type: :runtime
|
29
29
|
prerelease: false
|
30
30
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
version: '5.1'
|
35
35
|
- - "<"
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: '
|
37
|
+
version: '7.1'
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
39
|
name: activesupport
|
40
40
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,7 +44,7 @@ dependencies:
|
|
44
44
|
version: '5.1'
|
45
45
|
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '7.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '5.1'
|
55
55
|
- - "<"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: '
|
57
|
+
version: '7.1'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: bump
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,8 +197,11 @@ files:
|
|
197
197
|
- lib/active_record_shards/configuration_parser.rb
|
198
198
|
- lib/active_record_shards/connection_switcher-5-1.rb
|
199
199
|
- lib/active_record_shards/connection_switcher-6-0.rb
|
200
|
+
- lib/active_record_shards/connection_switcher-6-1.rb
|
201
|
+
- lib/active_record_shards/connection_switcher-7-0.rb
|
200
202
|
- lib/active_record_shards/connection_switcher.rb
|
201
203
|
- lib/active_record_shards/default_replica_patches.rb
|
204
|
+
- lib/active_record_shards/default_shard.rb
|
202
205
|
- lib/active_record_shards/migration.rb
|
203
206
|
- lib/active_record_shards/model.rb
|
204
207
|
- lib/active_record_shards/schema_dumper_extension.rb
|
@@ -210,7 +213,7 @@ homepage: https://github.com/zendesk/active_record_shards
|
|
210
213
|
licenses:
|
211
214
|
- MIT
|
212
215
|
metadata: {}
|
213
|
-
post_install_message:
|
216
|
+
post_install_message:
|
214
217
|
rdoc_options: []
|
215
218
|
require_paths:
|
216
219
|
- lib
|
@@ -225,8 +228,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
228
|
- !ruby/object:Gem::Version
|
226
229
|
version: '0'
|
227
230
|
requirements: []
|
228
|
-
rubygems_version: 3.1
|
229
|
-
signing_key:
|
231
|
+
rubygems_version: 3.0.3.1
|
232
|
+
signing_key:
|
230
233
|
specification_version: 4
|
231
234
|
summary: Simple database switching for ActiveRecord.
|
232
235
|
test_files: []
|