switchman 3.0.6 → 3.1.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/Rakefile +1 -1
- data/lib/switchman/action_controller/caching.rb +2 -2
- data/lib/switchman/active_record/abstract_adapter.rb +2 -4
- data/lib/switchman/active_record/associations.rb +223 -0
- data/lib/switchman/active_record/attribute_methods.rb +144 -84
- data/lib/switchman/active_record/base.rb +71 -31
- data/lib/switchman/active_record/calculations.rb +12 -5
- data/lib/switchman/active_record/connection_pool.rb +2 -4
- data/lib/switchman/active_record/database_configurations.rb +18 -2
- data/lib/switchman/active_record/finder_methods.rb +2 -2
- data/lib/switchman/active_record/model_schema.rb +1 -1
- data/lib/switchman/active_record/persistence.rb +3 -5
- data/lib/switchman/active_record/postgresql_adapter.rb +1 -1
- data/lib/switchman/active_record/query_methods.rb +23 -14
- data/lib/switchman/active_record/reflection.rb +1 -1
- data/lib/switchman/active_record/relation.rb +15 -18
- data/lib/switchman/active_record/statement_cache.rb +2 -2
- data/lib/switchman/active_record/table_definition.rb +1 -1
- data/lib/switchman/active_support/cache.rb +16 -0
- data/lib/switchman/arel.rb +28 -6
- data/lib/switchman/database_server.rb +28 -20
- data/lib/switchman/default_shard.rb +0 -2
- data/lib/switchman/engine.rb +63 -125
- data/lib/switchman/errors.rb +4 -2
- data/lib/switchman/guard_rail/relation.rb +6 -9
- data/lib/switchman/guard_rail.rb +5 -0
- data/lib/switchman/parallel.rb +68 -0
- data/lib/switchman/r_spec_helper.rb +8 -0
- data/lib/switchman/rails.rb +1 -4
- data/{app/models → lib}/switchman/shard.rb +30 -131
- data/lib/switchman/sharded_instrumenter.rb +1 -1
- data/lib/switchman/standard_error.rb +10 -11
- data/{app/models → lib}/switchman/unsharded_record.rb +1 -1
- data/lib/switchman/version.rb +1 -1
- data/lib/switchman.rb +22 -2
- data/lib/tasks/switchman.rake +16 -9
- metadata +19 -18
- data/lib/switchman/active_record/association.rb +0 -206
- data/lib/switchman/open4.rb +0 -80
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'switchman/database_server'
|
|
4
|
-
require 'switchman/default_shard'
|
|
5
|
-
require 'switchman/environment'
|
|
6
|
-
require 'switchman/errors'
|
|
7
|
-
|
|
8
3
|
module Switchman
|
|
9
4
|
class Shard < UnshardedRecord
|
|
10
5
|
# ten trillion possible ids per shard. yup.
|
|
@@ -42,14 +37,9 @@ module Switchman
|
|
|
42
37
|
# Now find the actual record, if it exists
|
|
43
38
|
@default = begin
|
|
44
39
|
find_cached('default_shard') { Shard.where(default: true).take } || default
|
|
45
|
-
# If we are *super* early in boot, the connection pool won't exist; we don't want to fill in the default shard yet
|
|
46
|
-
rescue ::ActiveRecord::ConnectionNotEstablished
|
|
47
|
-
nil
|
|
48
|
-
# rescue the fake default if the table doesn't exist
|
|
49
40
|
rescue
|
|
50
41
|
default
|
|
51
42
|
end
|
|
52
|
-
return default unless @default
|
|
53
43
|
|
|
54
44
|
# make sure this is not erroneously cached
|
|
55
45
|
@default.database_server.remove_instance_variable(:@primary_shard) if @default.database_server.instance_variable_defined?(:@primary_shard)
|
|
@@ -127,8 +117,7 @@ module Switchman
|
|
|
127
117
|
# * +classes+ - an array of classes to activate
|
|
128
118
|
# parallel: - true/false to execute in parallel, or an integer of how many
|
|
129
119
|
# sub-processes. Note that parallel invocation currently uses
|
|
130
|
-
# forking
|
|
131
|
-
# results back
|
|
120
|
+
# forking.
|
|
132
121
|
# exception: - :ignore, :raise, :defer (wait until the end and raise the first
|
|
133
122
|
# error), or a proc
|
|
134
123
|
def with_each_shard(*args, parallel: false, exception: :raise, &block)
|
|
@@ -160,138 +149,48 @@ module Switchman
|
|
|
160
149
|
# nothing to do
|
|
161
150
|
return if database_servers.count.zero?
|
|
162
151
|
|
|
163
|
-
scopes = database_servers.
|
|
164
|
-
[server, server.shards
|
|
165
|
-
end
|
|
152
|
+
scopes = database_servers.to_h do |server|
|
|
153
|
+
[server, scope.merge(server.shards)]
|
|
154
|
+
end
|
|
166
155
|
else
|
|
167
156
|
scopes = scope.group_by(&:database_server)
|
|
168
157
|
end
|
|
169
158
|
|
|
170
|
-
exception_pipes = []
|
|
171
|
-
pids = []
|
|
172
|
-
out_fds = []
|
|
173
|
-
err_fds = []
|
|
174
|
-
pid_to_name_map = {}
|
|
175
|
-
fd_to_name_map = {}
|
|
176
|
-
errors = []
|
|
177
|
-
|
|
178
|
-
wait_for_output = lambda do
|
|
179
|
-
ready, = IO.select(out_fds + err_fds)
|
|
180
|
-
ready.each do |fd|
|
|
181
|
-
if fd.eof?
|
|
182
|
-
fd.close
|
|
183
|
-
out_fds.delete(fd)
|
|
184
|
-
err_fds.delete(fd)
|
|
185
|
-
next
|
|
186
|
-
end
|
|
187
|
-
line = fd.readline
|
|
188
|
-
puts "#{fd_to_name_map[fd]}: #{line}"
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# only one process; don't bother forking
|
|
193
|
-
return with_each_shard(scopes.first.last, classes, exception: exception, &block) if scopes.length == 1
|
|
194
|
-
|
|
195
159
|
# clear connections prior to forking (no more queries will be executed in the parent,
|
|
196
160
|
# and we want them gone so that we don't accidentally use them post-fork doing something
|
|
197
161
|
# silly like dealloc'ing prepared statements)
|
|
198
162
|
::ActiveRecord::Base.clear_all_connections!
|
|
199
163
|
|
|
200
|
-
|
|
164
|
+
parent_process_name = `ps -ocommand= -p#{Process.pid}`.slice(/#{$0}.*/)
|
|
165
|
+
ret = ::Parallel.map(scopes, in_processes: scopes.length > 1 ? parallel : 0) do |server, subscope|
|
|
201
166
|
name = server.id
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
# was started)
|
|
211
|
-
# first, simplify the binary name by stripping directories,
|
|
212
|
-
# then truncate arguments as necessary
|
|
213
|
-
bin = File.basename($0) # Process.argv0 doesn't work on Ruby 2.5 (https://bugs.ruby-lang.org/issues/15887)
|
|
214
|
-
max_length = 128 - bin.length - name.length - 3
|
|
215
|
-
args = ARGV.join(' ')
|
|
216
|
-
args = args[0..max_length] if max_length >= 0
|
|
217
|
-
new_title = [bin, args, name].join(' ')
|
|
167
|
+
# rubocop:disable Style/GlobalStdStream
|
|
168
|
+
$stdout = Parallel::PrefixingIO.new(name, STDOUT)
|
|
169
|
+
$stderr = Parallel::PrefixingIO.new(name, STDERR)
|
|
170
|
+
# rubocop:enable Style/GlobalStdStream
|
|
171
|
+
begin
|
|
172
|
+
max_length = 128 - name.length - 3
|
|
173
|
+
short_parent_name = parent_process_name[0..max_length] if max_length >= 0
|
|
174
|
+
new_title = [short_parent_name, name].join(' ')
|
|
218
175
|
Process.setproctitle(new_title)
|
|
219
|
-
|
|
220
|
-
with_each_shard(subscope, classes, exception: exception, &block)
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
dumped = Marshal.dump(e)
|
|
225
|
-
dumped = nil if dumped.length > 64 * 1024
|
|
226
|
-
rescue
|
|
227
|
-
dumped = nil
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
if dumped.nil?
|
|
231
|
-
# couldn't dump the exception; create a copy with just
|
|
232
|
-
# the message and the backtrace
|
|
233
|
-
e2 = e.class.new(e.message)
|
|
234
|
-
backtrace = e.backtrace
|
|
235
|
-
# truncate excessively long backtraces
|
|
236
|
-
backtrace = backtrace[0...25] + ['...'] + backtrace[-25..] if backtrace.length > 50
|
|
237
|
-
e2.set_backtrace(backtrace)
|
|
238
|
-
e2.instance_variable_set(:@active_shards, e.instance_variable_get(:@active_shards))
|
|
239
|
-
dumped = Marshal.dump(e2)
|
|
240
|
-
end
|
|
241
|
-
exception_pipe.last.set_encoding(dumped.encoding)
|
|
242
|
-
exception_pipe.last.write(dumped)
|
|
243
|
-
exception_pipe.last.flush
|
|
244
|
-
exception_pipe.last.close
|
|
245
|
-
exit! 1
|
|
246
|
-
end)
|
|
247
|
-
exception_pipe.last.close
|
|
248
|
-
pids << pid
|
|
249
|
-
io_in.close # don't care about writing to stdin
|
|
250
|
-
out_fds << io_out
|
|
251
|
-
err_fds << io_err
|
|
252
|
-
pid_to_name_map[pid] = name
|
|
253
|
-
fd_to_name_map[io_out] = name
|
|
254
|
-
fd_to_name_map[io_err] = name
|
|
255
|
-
|
|
256
|
-
while pids.count >= parallel
|
|
257
|
-
while out_fds.count >= parallel
|
|
258
|
-
# wait for output if we've hit the parallel limit
|
|
259
|
-
wait_for_output.call
|
|
260
|
-
end
|
|
261
|
-
# we've gotten all the output from one fd so wait for its child process to exit
|
|
262
|
-
found_pid, status = Process.wait2
|
|
263
|
-
pids.delete(found_pid)
|
|
264
|
-
errors << pid_to_name_map[found_pid] if status.exitstatus != 0
|
|
176
|
+
Switchman.config[:on_fork_proc]&.call
|
|
177
|
+
with_each_shard(subscope, classes, exception: exception, &block).map { |result| Parallel::ResultWrapper.new(result) }
|
|
178
|
+
rescue => e
|
|
179
|
+
logger.error e.full_message
|
|
180
|
+
Parallel::QuietExceptionWrapper.new(name, ::Parallel::ExceptionWrapper.new(e))
|
|
265
181
|
end
|
|
266
|
-
|
|
267
|
-
found_pid, status = Process.wait2
|
|
268
|
-
pids.delete(found_pid)
|
|
269
|
-
errors << pid_to_name_map[found_pid] if status.exitstatus != 0
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
wait_for_output.call while out_fds.any? || err_fds.any?
|
|
273
|
-
pids.each do |pid|
|
|
274
|
-
_, status = Process.waitpid2(pid)
|
|
275
|
-
errors << pid_to_name_map[pid] if status.exitstatus != 0
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
# check for an exception; we only re-raise the first one
|
|
279
|
-
exception_pipes.each do |exception_pipe|
|
|
280
|
-
serialized_exception = exception_pipe.first.read
|
|
281
|
-
next if serialized_exception.empty?
|
|
282
|
-
|
|
283
|
-
ex = Marshal.load(serialized_exception) # rubocop:disable Security/MarshalLoad
|
|
284
|
-
raise ex
|
|
285
|
-
ensure
|
|
286
|
-
exception_pipe.first.close
|
|
287
|
-
end
|
|
182
|
+
end.flatten
|
|
288
183
|
|
|
184
|
+
errors = ret.select { |val| val.is_a?(Parallel::QuietExceptionWrapper) }
|
|
289
185
|
unless errors.empty?
|
|
290
|
-
raise
|
|
291
|
-
|
|
186
|
+
raise errors.first.exception if errors.length == 1
|
|
187
|
+
|
|
188
|
+
raise Errors::ParallelShardExecError,
|
|
189
|
+
"The following database server(s) did not finish processing cleanly: #{errors.map(&:name).sort.join(', ')}",
|
|
190
|
+
cause: errors.first.exception
|
|
292
191
|
end
|
|
293
192
|
|
|
294
|
-
return
|
|
193
|
+
return ret.map(&:result)
|
|
295
194
|
end
|
|
296
195
|
|
|
297
196
|
classes ||= []
|
|
@@ -471,11 +370,11 @@ module Switchman
|
|
|
471
370
|
|
|
472
371
|
def add_sharded_model(klass)
|
|
473
372
|
@sharded_models = (sharded_models + [klass]).freeze
|
|
474
|
-
|
|
373
|
+
configure_connects_to
|
|
475
374
|
end
|
|
476
375
|
|
|
477
|
-
def
|
|
478
|
-
full_connects_to_hash = DatabaseServer.all.
|
|
376
|
+
def configure_connects_to
|
|
377
|
+
full_connects_to_hash = DatabaseServer.all.to_h { |db| [db.id.to_sym, db.connects_to_hash] }
|
|
479
378
|
sharded_models.each do |klass|
|
|
480
379
|
connects_to_hash = full_connects_to_hash.deep_dup
|
|
481
380
|
if klass == UnshardedRecord
|
|
@@ -16,7 +16,7 @@ module Switchman
|
|
|
16
16
|
payload[:shard] = {
|
|
17
17
|
database_server_id: shard.database_server.id,
|
|
18
18
|
id: shard.id,
|
|
19
|
-
env:
|
|
19
|
+
env: ::Rails.version < '7.0' ? @shard_host.pool.connection_klass&.current_role : @shard_host.pool.connection_class&.current_role
|
|
20
20
|
}
|
|
21
21
|
end
|
|
22
22
|
super name, payload
|
|
@@ -3,20 +3,19 @@
|
|
|
3
3
|
module Switchman
|
|
4
4
|
module StandardError
|
|
5
5
|
def initialize(*args)
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
if is_a?(::
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
end
|
|
6
|
+
super
|
|
7
|
+
# These seem to get themselves into a bad state if we try to lookup shards while processing
|
|
8
|
+
return if is_a?(IO::EAGAINWaitReadable)
|
|
9
|
+
|
|
10
|
+
return if Thread.current[:switchman_error_handler]
|
|
12
11
|
|
|
13
12
|
begin
|
|
14
|
-
|
|
15
|
-
rescue ::ActiveRecord::ConnectionNotEstablished
|
|
16
|
-
# If we hit an error really early in boot, activerecord may not be initialized yet
|
|
17
|
-
end
|
|
13
|
+
Thread.current[:switchman_error_handler] = true
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
@active_shards ||= Shard.active_shards
|
|
16
|
+
ensure
|
|
17
|
+
Thread.current[:switchman_error_handler] = nil
|
|
18
|
+
end
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
def current_shard(klass = ::ActiveRecord::Base)
|
data/lib/switchman/version.rb
CHANGED
data/lib/switchman.rb
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'guard_rail'
|
|
4
|
-
require '
|
|
5
|
-
|
|
4
|
+
require 'zeitwerk'
|
|
5
|
+
|
|
6
|
+
class SwitchmanInflector < Zeitwerk::GemInflector
|
|
7
|
+
def camelize(basename, abspath)
|
|
8
|
+
if basename =~ /\Apostgresql_(.*)/
|
|
9
|
+
'PostgreSQL' + super($1, abspath)
|
|
10
|
+
else
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
loader = Zeitwerk::Loader.for_gem
|
|
17
|
+
loader.inflector = SwitchmanInflector.new(__FILE__)
|
|
18
|
+
loader.setup
|
|
6
19
|
|
|
7
20
|
module Switchman
|
|
8
21
|
def self.config
|
|
@@ -18,5 +31,12 @@ module Switchman
|
|
|
18
31
|
@cache = cache
|
|
19
32
|
end
|
|
20
33
|
|
|
34
|
+
def self.foreign_key_check(name, type, limit: nil)
|
|
35
|
+
puts "WARNING: All foreign keys need to be 8-byte integers. #{name} looks like a foreign key. If so, please add the option: `:limit => 8`" if name.to_s =~ /_id\z/ && type.to_s == 'integer' && limit.to_i < 8
|
|
36
|
+
end
|
|
37
|
+
|
|
21
38
|
class OrderOnMultiShardQuery < RuntimeError; end
|
|
22
39
|
end
|
|
40
|
+
|
|
41
|
+
# Load the engine and everything associated at gem load time
|
|
42
|
+
Switchman::Engine
|
data/lib/tasks/switchman.rake
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# In rails 7.0+ if you have only 1 db in the env it doesn't try to do explicit activation
|
|
4
|
+
# (and for rails purposes we only have one db per env because each database server is a separate env)
|
|
5
|
+
if Rails.version < '7.0'
|
|
6
|
+
task_prefix = ::Rake::Task.task_defined?('app:db:migrate') ? 'app:db' : 'db'
|
|
7
|
+
::Rake::Task["#{task_prefix}:migrate"].clear_actions.enhance do
|
|
8
|
+
::ActiveRecord::Tasks::DatabaseTasks.migrate
|
|
9
|
+
# Ensure this doesn't blow up when running inside the dummy app
|
|
10
|
+
Rake::Task["#{task_prefix}:_dump"].invoke
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
3
14
|
module Switchman
|
|
4
15
|
module Rake
|
|
5
16
|
def self.filter_database_servers(&block)
|
|
@@ -35,9 +46,9 @@ module Switchman
|
|
|
35
46
|
|
|
36
47
|
scope = base_scope.order(::Arel.sql('database_server_id IS NOT NULL, database_server_id, id'))
|
|
37
48
|
if servers != DatabaseServer.all
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
scope = scope.where(
|
|
49
|
+
database_server_ids = servers.map(&:id)
|
|
50
|
+
database_server_ids << nil if servers.include?(Shard.default.database_server)
|
|
51
|
+
scope = scope.where(database_server_id: database_server_ids)
|
|
41
52
|
end
|
|
42
53
|
|
|
43
54
|
scope = shard_scope(scope, shard) if shard
|
|
@@ -50,9 +61,7 @@ module Switchman
|
|
|
50
61
|
end
|
|
51
62
|
|
|
52
63
|
# classes - an array or proc, to activate as the current shard during the
|
|
53
|
-
# task.
|
|
54
|
-
# so that schema updates for non-default tables happen against all shards.
|
|
55
|
-
# this is handled automatically for the default migration tasks, below.
|
|
64
|
+
# task.
|
|
56
65
|
def self.shardify_task(task_name, classes: [::ActiveRecord::Base])
|
|
57
66
|
old_task = ::Rake::Task[task_name]
|
|
58
67
|
old_actions = old_task.actions.dup
|
|
@@ -77,10 +86,8 @@ module Switchman
|
|
|
77
86
|
nil
|
|
78
87
|
end
|
|
79
88
|
rescue => e
|
|
80
|
-
|
|
89
|
+
warn "Exception from #{e.current_shard.id}: #{e.current_shard.description}:\n#{e.full_message}" if options[:parallel] != 0
|
|
81
90
|
raise
|
|
82
|
-
|
|
83
|
-
# ::ActiveRecord::Base.configurations = old_configurations
|
|
84
91
|
end
|
|
85
92
|
end
|
|
86
93
|
end
|
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.0
|
|
4
|
+
version: 3.1.0
|
|
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: 2022-02
|
|
13
|
+
date: 2022-06-02 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activerecord
|
|
@@ -21,7 +21,7 @@ dependencies:
|
|
|
21
21
|
version: 6.1.4
|
|
22
22
|
- - "<"
|
|
23
23
|
- !ruby/object:Gem::Version
|
|
24
|
-
version: '
|
|
24
|
+
version: '7.1'
|
|
25
25
|
type: :runtime
|
|
26
26
|
prerelease: false
|
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -31,35 +31,35 @@ dependencies:
|
|
|
31
31
|
version: 6.1.4
|
|
32
32
|
- - "<"
|
|
33
33
|
- !ruby/object:Gem::Version
|
|
34
|
-
version: '
|
|
34
|
+
version: '7.1'
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
36
|
name: guardrail
|
|
37
37
|
requirement: !ruby/object:Gem::Requirement
|
|
38
38
|
requirements:
|
|
39
39
|
- - "~>"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version: 3.0.
|
|
41
|
+
version: 3.0.1
|
|
42
42
|
type: :runtime
|
|
43
43
|
prerelease: false
|
|
44
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
46
|
- - "~>"
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: 3.0.
|
|
48
|
+
version: 3.0.1
|
|
49
49
|
- !ruby/object:Gem::Dependency
|
|
50
|
-
name:
|
|
50
|
+
name: parallel
|
|
51
51
|
requirement: !ruby/object:Gem::Requirement
|
|
52
52
|
requirements:
|
|
53
53
|
- - "~>"
|
|
54
54
|
- !ruby/object:Gem::Version
|
|
55
|
-
version: 1.
|
|
55
|
+
version: '1.22'
|
|
56
56
|
type: :runtime
|
|
57
57
|
prerelease: false
|
|
58
58
|
version_requirements: !ruby/object:Gem::Requirement
|
|
59
59
|
requirements:
|
|
60
60
|
- - "~>"
|
|
61
61
|
- !ruby/object:Gem::Version
|
|
62
|
-
version: 1.
|
|
62
|
+
version: '1.22'
|
|
63
63
|
- !ruby/object:Gem::Dependency
|
|
64
64
|
name: railties
|
|
65
65
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -69,7 +69,7 @@ dependencies:
|
|
|
69
69
|
version: '6.1'
|
|
70
70
|
- - "<"
|
|
71
71
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '
|
|
72
|
+
version: '7.1'
|
|
73
73
|
type: :runtime
|
|
74
74
|
prerelease: false
|
|
75
75
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -79,7 +79,7 @@ dependencies:
|
|
|
79
79
|
version: '6.1'
|
|
80
80
|
- - "<"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '
|
|
82
|
+
version: '7.1'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: appraisal
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -242,8 +242,6 @@ extensions: []
|
|
|
242
242
|
extra_rdoc_files: []
|
|
243
243
|
files:
|
|
244
244
|
- Rakefile
|
|
245
|
-
- app/models/switchman/shard.rb
|
|
246
|
-
- app/models/switchman/unsharded_record.rb
|
|
247
245
|
- db/migrate/20130328212039_create_switchman_shards.rb
|
|
248
246
|
- db/migrate/20130328224244_create_default_shard.rb
|
|
249
247
|
- db/migrate/20161206323434_add_back_default_string_limits_switchman.rb
|
|
@@ -253,7 +251,7 @@ files:
|
|
|
253
251
|
- lib/switchman.rb
|
|
254
252
|
- lib/switchman/action_controller/caching.rb
|
|
255
253
|
- lib/switchman/active_record/abstract_adapter.rb
|
|
256
|
-
- lib/switchman/active_record/
|
|
254
|
+
- lib/switchman/active_record/associations.rb
|
|
257
255
|
- lib/switchman/active_record/attribute_methods.rb
|
|
258
256
|
- lib/switchman/active_record/base.rb
|
|
259
257
|
- lib/switchman/active_record/calculations.rb
|
|
@@ -287,18 +285,21 @@ files:
|
|
|
287
285
|
- lib/switchman/errors.rb
|
|
288
286
|
- lib/switchman/guard_rail.rb
|
|
289
287
|
- lib/switchman/guard_rail/relation.rb
|
|
290
|
-
- lib/switchman/
|
|
288
|
+
- lib/switchman/parallel.rb
|
|
291
289
|
- lib/switchman/r_spec_helper.rb
|
|
292
290
|
- lib/switchman/rails.rb
|
|
291
|
+
- lib/switchman/shard.rb
|
|
293
292
|
- lib/switchman/sharded_instrumenter.rb
|
|
294
293
|
- lib/switchman/standard_error.rb
|
|
295
294
|
- lib/switchman/test_helper.rb
|
|
295
|
+
- lib/switchman/unsharded_record.rb
|
|
296
296
|
- lib/switchman/version.rb
|
|
297
297
|
- lib/tasks/switchman.rake
|
|
298
298
|
homepage: http://www.instructure.com/
|
|
299
299
|
licenses:
|
|
300
300
|
- MIT
|
|
301
|
-
metadata:
|
|
301
|
+
metadata:
|
|
302
|
+
rubygems_mfa_required: 'true'
|
|
302
303
|
post_install_message:
|
|
303
304
|
rdoc_options: []
|
|
304
305
|
require_paths:
|
|
@@ -307,14 +308,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
307
308
|
requirements:
|
|
308
309
|
- - ">="
|
|
309
310
|
- !ruby/object:Gem::Version
|
|
310
|
-
version: '2.
|
|
311
|
+
version: '2.7'
|
|
311
312
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
312
313
|
requirements:
|
|
313
314
|
- - ">="
|
|
314
315
|
- !ruby/object:Gem::Version
|
|
315
316
|
version: '0'
|
|
316
317
|
requirements: []
|
|
317
|
-
rubygems_version: 3.1.
|
|
318
|
+
rubygems_version: 3.1.6
|
|
318
319
|
signing_key:
|
|
319
320
|
specification_version: 4
|
|
320
321
|
summary: Rails sharding magic
|