switchman 3.5.13 → 3.5.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/switchman/active_record/base.rb +6 -1
- data/lib/switchman/database_server.rb +31 -0
- data/lib/switchman/default_shard.rb +11 -0
- data/lib/switchman/r_spec_helper.rb +1 -1
- data/lib/switchman/shard.rb +51 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +21 -17
- data/lib/tasks/switchman.rake +14 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 243c4f20483016069c4c18efd47a64a8b2078596f254c1152f4f2a70555054f0
|
4
|
+
data.tar.gz: 332d8e5a2d5e119d1599e259f27fa1ba25e9f3139cc7504bd159aebcb730e724
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53604b1eedb8bd5ca453d617eb7e4c83ad5080bad4ccb2dff0cced4be2baaeccbe139d7b5936face689e2ccbd94cac338d39f7ecf2ace8a25f61f81fe47ed0c8
|
7
|
+
data.tar.gz: 5f9b8523159c6eeec8275838a825c9c911ad136ef33d32d362e80ce63008f130e7789f1863b851d9527c68591bcbcfa6aa95183f2b6cca5eef7e55096194abb4
|
@@ -57,7 +57,12 @@ module Switchman
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def clear_query_caches_for_current_thread
|
60
|
-
::
|
60
|
+
pools = if ::Rails.version < "7.1"
|
61
|
+
::ActiveRecord::Base.connection_handler.connection_pool_list
|
62
|
+
else
|
63
|
+
::ActiveRecord::Base.connection_handler.connection_pool_list(:all)
|
64
|
+
end
|
65
|
+
pools.each do |pool|
|
61
66
|
pool.connection(switch_shard: false).clear_query_cache if pool.active_connection?
|
62
67
|
end
|
63
68
|
end
|
@@ -10,6 +10,10 @@ module Switchman
|
|
10
10
|
attr_accessor :creating_new_shard
|
11
11
|
attr_reader :all_roles
|
12
12
|
|
13
|
+
include Enumerable
|
14
|
+
|
15
|
+
delegate :each, to: :all
|
16
|
+
|
13
17
|
def all
|
14
18
|
database_servers.values
|
15
19
|
end
|
@@ -50,6 +54,10 @@ module Switchman
|
|
50
54
|
all.each { |db| db.guard! if db.config[:prefer_secondary] }
|
51
55
|
end
|
52
56
|
|
57
|
+
def regions
|
58
|
+
@regions ||= all.filter_map(&:region).uniq.sort
|
59
|
+
end
|
60
|
+
|
53
61
|
private
|
54
62
|
|
55
63
|
def reference_role(role)
|
@@ -140,6 +148,29 @@ module Switchman
|
|
140
148
|
end
|
141
149
|
end
|
142
150
|
|
151
|
+
def region
|
152
|
+
config[:region]
|
153
|
+
end
|
154
|
+
|
155
|
+
# @param region [String, Array<String>] the region(s) to check against
|
156
|
+
# @return true if the database server doesn't have a region, or it
|
157
|
+
# matches the specified region
|
158
|
+
def in_region?(region)
|
159
|
+
!self.region || (region.is_a?(Array) ? region.include?(self.region) : self.region == region)
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return true if the database server doesn't have a region, Switchman is
|
163
|
+
# not configured with a region, or the database server's region matches
|
164
|
+
# Switchman's current region
|
165
|
+
def in_current_region?
|
166
|
+
unless instance_variable_defined?(:@in_current_region)
|
167
|
+
@in_current_region = !region ||
|
168
|
+
!Switchman.region ||
|
169
|
+
region == Switchman.region
|
170
|
+
end
|
171
|
+
@in_current_region
|
172
|
+
end
|
173
|
+
|
143
174
|
# locks this db to a specific environment, except for
|
144
175
|
# when doing writes (then it falls back to the current
|
145
176
|
# value of GuardRail.environment)
|
@@ -6,6 +6,7 @@ module Switchman
|
|
6
6
|
"default"
|
7
7
|
end
|
8
8
|
alias_method :cache_key, :id
|
9
|
+
|
9
10
|
def activate(*_classes)
|
10
11
|
yield
|
11
12
|
end
|
@@ -57,6 +58,16 @@ module Switchman
|
|
57
58
|
self
|
58
59
|
end
|
59
60
|
|
61
|
+
def region; end
|
62
|
+
|
63
|
+
def in_region?(_region)
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def in_current_region?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
60
71
|
def _dump(_depth)
|
61
72
|
""
|
62
73
|
end
|
@@ -121,7 +121,7 @@ module Switchman
|
|
121
121
|
next if @@sharding_failed
|
122
122
|
|
123
123
|
# clean up after specs
|
124
|
-
DatabaseServer.
|
124
|
+
DatabaseServer.each do |ds|
|
125
125
|
if ds.fake? && ds != @shard2.database_server
|
126
126
|
ds.shards.delete_all unless use_transactional_tests
|
127
127
|
ds.destroy
|
data/lib/switchman/shard.rb
CHANGED
@@ -13,6 +13,47 @@ module Switchman
|
|
13
13
|
|
14
14
|
scope :primary, -> { where(name: nil).order(:database_server_id, :id).distinct_on(:database_server_id) }
|
15
15
|
|
16
|
+
scope :in_region, (lambda do |region, include_regionless: true|
|
17
|
+
next in_current_region if region.nil?
|
18
|
+
|
19
|
+
dbs_by_region = DatabaseServer.group_by(&:region)
|
20
|
+
db_count_in_this_region = dbs_by_region[region]&.length.to_i
|
21
|
+
db_count_in_this_region += dbs_by_region[nil]&.length.to_i if include_regionless
|
22
|
+
non_existent_database_servers = Shard.send(:non_existent_database_servers)
|
23
|
+
db_count_in_other_regions = DatabaseServer.all.length -
|
24
|
+
db_count_in_this_region +
|
25
|
+
non_existent_database_servers.length
|
26
|
+
|
27
|
+
dbs_in_this_region = dbs_by_region[region]&.map(&:id) || []
|
28
|
+
dbs_in_this_region += dbs_by_region[nil]&.map(&:id) || [] if include_regionless
|
29
|
+
|
30
|
+
if db_count_in_this_region <= db_count_in_other_regions
|
31
|
+
if dbs_in_this_region.include?(Shard.default.database_server.id)
|
32
|
+
where("database_server_id IN (?) OR database_server_id IS NULL", dbs_in_this_region)
|
33
|
+
else
|
34
|
+
where(database_server_id: dbs_in_this_region)
|
35
|
+
end
|
36
|
+
elsif db_count_in_other_regions.zero?
|
37
|
+
all
|
38
|
+
else
|
39
|
+
dbs_not_in_this_region = DatabaseServer.map(&:id) - dbs_in_this_region + non_existent_database_servers
|
40
|
+
if dbs_in_this_region.include?(Shard.default.database_server.id)
|
41
|
+
where("database_server_id NOT IN (?) OR database_server_id IS NULL", dbs_not_in_this_region)
|
42
|
+
else
|
43
|
+
where.not(database_server_id: dbs_not_in_this_region)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end)
|
47
|
+
|
48
|
+
scope :in_current_region, (lambda do |include_regionless: true|
|
49
|
+
# sharding isn't set up? maybe we're in tests, or a somehow degraded environment
|
50
|
+
# either way there's only one shard, and we always want to see it
|
51
|
+
return [default] unless default.is_a?(Switchman::Shard)
|
52
|
+
return all if !Switchman.region || DatabaseServer.none?(&:region)
|
53
|
+
|
54
|
+
in_region(Switchman.region, include_regionless: include_regionless)
|
55
|
+
end)
|
56
|
+
|
16
57
|
class << self
|
17
58
|
def sharded_models
|
18
59
|
@sharded_models ||= [::ActiveRecord::Base, UnshardedRecord].freeze
|
@@ -395,7 +436,7 @@ module Switchman
|
|
395
436
|
end
|
396
437
|
|
397
438
|
def configure_connects_to
|
398
|
-
full_connects_to_hash = DatabaseServer.
|
439
|
+
full_connects_to_hash = DatabaseServer.to_h { |db| [db.id.to_sym, db.connects_to_hash] }
|
399
440
|
sharded_models.each do |klass|
|
400
441
|
connects_to_hash = full_connects_to_hash.deep_dup
|
401
442
|
if klass == UnshardedRecord
|
@@ -484,8 +525,17 @@ module Switchman
|
|
484
525
|
argv[0] = File.basename(argv[0])
|
485
526
|
argv.shelljoin
|
486
527
|
end
|
528
|
+
|
529
|
+
# @return [Array<String>] the list of database servers that are in the
|
530
|
+
# config, but don't have any shards on them
|
531
|
+
def non_existent_database_servers
|
532
|
+
@non_existent_database_servers ||=
|
533
|
+
Shard.distinct.pluck(:database_server_id).compact - DatabaseServer.all.map(&:id)
|
534
|
+
end
|
487
535
|
end
|
488
536
|
|
537
|
+
delegate :region, :in_region?, :in_current_region?, to: :database_server
|
538
|
+
|
489
539
|
def name
|
490
540
|
unless instance_variable_defined?(:@name)
|
491
541
|
# protect against re-entrancy
|
data/lib/switchman/version.rb
CHANGED
data/lib/switchman.rb
CHANGED
@@ -20,27 +20,31 @@ loader.setup
|
|
20
20
|
module Switchman
|
21
21
|
Deprecation = ::ActiveSupport::Deprecation.new("4.0", "Switchman")
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
@config ||= {}
|
26
|
-
end
|
23
|
+
class << self
|
24
|
+
attr_writer :cache
|
27
25
|
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
def config
|
27
|
+
# TODO: load from yaml
|
28
|
+
@config ||= {}
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
def cache
|
32
|
+
(@cache.respond_to?(:call) ? @cache.call : @cache) || ::Rails.cache
|
33
|
+
end
|
34
|
+
|
35
|
+
def region
|
36
|
+
config[:region]
|
37
|
+
end
|
35
38
|
|
36
|
-
|
37
|
-
|
39
|
+
def foreign_key_check(name, type, limit: nil)
|
40
|
+
return unless name.to_s.end_with?("_id") && type.to_s == "integer" && limit.to_i < 8
|
38
41
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
puts <<~TEXT.squish
|
43
|
+
WARNING: All foreign keys need to be 8-byte integers.
|
44
|
+
#{name} looks like a foreign key.
|
45
|
+
If so, please add the option: `:limit => 8`
|
46
|
+
TEXT
|
47
|
+
end
|
44
48
|
end
|
45
49
|
|
46
50
|
class OrderOnMultiShardQuery < RuntimeError; end
|
data/lib/tasks/switchman.rake
CHANGED
@@ -35,7 +35,7 @@ module Switchman
|
|
35
35
|
|
36
36
|
servers = servers.filter_map { |server| DatabaseServer.find(server) }
|
37
37
|
if open
|
38
|
-
open_servers = DatabaseServer.
|
38
|
+
open_servers = DatabaseServer.select { |server| server.config[:open] }
|
39
39
|
servers.concat(open_servers)
|
40
40
|
servers << DatabaseServer.find(nil) if open_servers.empty?
|
41
41
|
servers.uniq!
|
@@ -43,6 +43,19 @@ module Switchman
|
|
43
43
|
servers = DatabaseServer.all - servers if negative
|
44
44
|
end
|
45
45
|
|
46
|
+
ENV["REGION"]&.split(",")&.each do |region|
|
47
|
+
method = :select!
|
48
|
+
if region[0] == "-"
|
49
|
+
method = :reject!
|
50
|
+
region = region[1..]
|
51
|
+
end
|
52
|
+
if region == "self"
|
53
|
+
servers.send(method, &:in_current_region?)
|
54
|
+
else
|
55
|
+
servers.send(method) { |server| server.in_region?(region) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
servers = filter_database_servers_chain.call(servers)
|
47
60
|
|
48
61
|
scope = base_scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: switchman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.5.
|
4
|
+
version: 3.5.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Cutrer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-10-
|
13
|
+
date: 2023-10-12 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|