switchman 2.1.0 → 2.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4ef7325514ffe64ab4fd53de062392b9edba2e7089ff35a8bbebfa475338a9d
4
- data.tar.gz: cb74519796fee752ec5dc5e5469e39db240fbf819b38ea8d1ff5ae75c939601a
3
+ metadata.gz: c6658f02bb242697d5c6b9d7e9c57ba3613295fddc1de3d618cb74ed125835aa
4
+ data.tar.gz: 05fa7e267a2d442d3f9862e041fe6f297e3272693dd15273bfb17ec86187450f
5
5
  SHA512:
6
- metadata.gz: 6583450d651aa95d06ad5d53a294bb2247ceee6fca42659a666da13378422fdaeeced89a772622de5671812fd7990531f470fd3d630870e6306d53e3e1ebc873
7
- data.tar.gz: d1c21d744f5b926620f32540ca5c5c68b86ba97355b1fb8548ea829ccb05702173228eb40bf25e729a773be210436cfeb369ac2918a8aacea4da63d59b294404
6
+ metadata.gz: 3651b8ad5d882571716507a49e264b90d70a318e436e816e9dbe2ec0b9ff70031f4bfa7fce4e04748bad8e4dad88a36d16eac4afa1b0c61e2f686ed138bb2ef5
7
+ data.tar.gz: d1d98111fc70a2786768b61856ae4a54ba914275628489d99f12b7de7b0a891d62e7c41189aad2a388941a0c9ce89742d6751c4078ff15b57660d63d390978ce
@@ -129,6 +129,11 @@ module Switchman
129
129
  cached_shards[id]
130
130
  end
131
131
 
132
+ def preload_cache
133
+ cached_shards.reverse_merge!(active_shards.values.index_by(&:id))
134
+ cached_shards.reverse_merge!(all.index_by(&:id))
135
+ end
136
+
132
137
  def clear_cache
133
138
  cached_shards.clear
134
139
  end
@@ -139,10 +144,9 @@ module Switchman
139
144
  # * +categories+ - an array of categories to activate
140
145
  # * +options+ -
141
146
  # :parallel - true/false to execute in parallel, or a integer of how many
142
- # sub-processes per database server. Note that parallel
143
- # invocation currently uses forking, so should be used sparingly
144
- # because errors are not raised, and you cannot get results back
145
- # :max_procs - only run this many parallel processes at a time
147
+ # sub-processes. Note that parallel invocation currently uses
148
+ # forking, so should be used sparingly because you cannot get
149
+ # results back
146
150
  # :exception - :ignore, :raise, :defer (wait until the end and raise the first
147
151
  # error), or a proc
148
152
  def with_each_shard(*args)
@@ -163,11 +167,14 @@ module Switchman
163
167
  scope, categories = args
164
168
  end
165
169
 
170
+ # back-compat
171
+ options[:parallel] = options.delete(:max_procs) if options.key?(:max_procs)
172
+
166
173
  parallel = case options[:parallel]
167
174
  when true
168
- 1
175
+ [Environment.cpu_count || 2, 2].min
169
176
  when false, nil
170
- 0
177
+ 1
171
178
  else
172
179
  options[:parallel]
173
180
  end
@@ -178,47 +185,19 @@ module Switchman
178
185
  scope = scope.order(::Arel.sql("database_server_id IS NOT NULL, database_server_id, id"))
179
186
  end
180
187
 
181
- if parallel > 0
182
- max_procs = determine_max_procs(options.delete(:max_procs), parallel)
188
+ if parallel > 1
183
189
  if ::ActiveRecord::Relation === scope
184
190
  # still need a post-uniq, cause the default database server could be NULL or Rails.env in the db
185
191
  database_servers = scope.reorder('database_server_id').select(:database_server_id).distinct.
186
192
  map(&:database_server).compact.uniq
187
193
  # nothing to do
188
194
  return if database_servers.count == 0
189
- parallel = [(max_procs.to_f / database_servers.count).ceil, parallel].min if max_procs
190
195
 
191
196
  scopes = Hash[database_servers.map do |server|
192
- server_scope = server.shards.merge(scope)
193
- if parallel == 1
194
- subscopes = [server_scope]
195
- else
196
- subscopes = []
197
- total = server_scope.count
198
- ranges = []
199
- server_scope.find_ids_in_ranges(:batch_size => (total.to_f / parallel).ceil) do |min, max|
200
- ranges << [min, max]
201
- end
202
- # create a half-open range on the last one
203
- ranges.last[1] = nil
204
- ranges.each do |min, max|
205
- subscope = server_scope.where("id>=?", min)
206
- subscope = subscope.where("id<=?", max) if max
207
- subscopes << subscope
208
- end
209
- end
210
- [server, subscopes]
197
+ [server, server.shards.merge(scope)]
211
198
  end]
212
199
  else
213
200
  scopes = scope.group_by(&:database_server)
214
- if parallel > 1
215
- parallel = [(max_procs.to_f / scopes.count).ceil, parallel].min if max_procs
216
- scopes = Hash[scopes.map do |(server, shards)|
217
- [server, shards.in_groups(parallel, false).compact]
218
- end]
219
- else
220
- scopes = Hash[scopes.map { |(server, shards)| [server, [shards]] }]
221
- end
222
201
  end
223
202
 
224
203
  exception_pipes = []
@@ -244,8 +223,8 @@ module Switchman
244
223
  end
245
224
 
246
225
  # only one process; don't bother forking
247
- if scopes.length == 1 && parallel == 1
248
- return with_each_shard(scopes.first.last.first, categories, options) { yield }
226
+ if scopes.length == 1
227
+ return with_each_shard(scopes.first.last, categories, options) { yield }
249
228
  end
250
229
 
251
230
  # clear connections prior to forking (no more queries will be executed in the parent,
@@ -253,84 +232,78 @@ module Switchman
253
232
  # silly like dealloc'ing prepared statements)
254
233
  ::ActiveRecord::Base.clear_all_connections!
255
234
 
256
- scopes.each do |server, subscopes|
257
- subscopes.each_with_index do |subscope, idx|
258
- if subscopes.length > 1
259
- name = "#{server.id} #{idx + 1}"
260
- else
261
- name = server.id
262
- end
235
+ scopes.each do |server, subscope|
236
+ name = server.id
237
+
238
+ exception_pipe = IO.pipe
239
+ exception_pipes << exception_pipe
240
+ pid, io_in, io_out, io_err = Open4.pfork4(lambda do
241
+ begin
242
+ Switchman.config[:on_fork_proc]&.call
243
+
244
+ # set a pretty name for the process title, up to 128 characters
245
+ # (we don't actually know the limit, depending on how the process
246
+ # was started)
247
+ # first, simplify the binary name by stripping directories,
248
+ # then truncate arguments as necessary
249
+ bin = File.basename($0) # Process.argv0 doesn't work on Ruby 2.5 (https://bugs.ruby-lang.org/issues/15887)
250
+ max_length = 128 - bin.length - name.length - 3
251
+ args = ARGV.join(" ")
252
+ if max_length >= 0
253
+ args = args[0..max_length]
254
+ end
255
+ new_title = [bin, args, name].join(" ")
256
+ Process.setproctitle(new_title)
263
257
 
264
- exception_pipe = IO.pipe
265
- exception_pipes << exception_pipe
266
- pid, io_in, io_out, io_err = Open4.pfork4(lambda do
258
+ with_each_shard(subscope, categories, options) { yield }
259
+ exception_pipe.last.close
260
+ rescue Exception => e
267
261
  begin
268
- Switchman.config[:on_fork_proc]&.call
269
-
270
- # set a pretty name for the process title, up to 128 characters
271
- # (we don't actually know the limit, depending on how the process
272
- # was started)
273
- # first, simplify the binary name by stripping directories,
274
- # then truncate arguments as necessary
275
- bin = File.basename($0) # Process.argv0 doesn't work on Ruby 2.5 (https://bugs.ruby-lang.org/issues/15887)
276
- max_length = 128 - bin.length - name.length - 3
277
- args = ARGV.join(" ")
278
- if max_length >= 0
279
- args = args[0..max_length]
280
- end
281
- new_title = [bin, args, name].join(" ")
282
- Process.setproctitle(new_title)
283
-
284
- with_each_shard(subscope, categories, options) { yield }
285
- exception_pipe.last.close
286
- rescue Exception => e
287
- begin
288
- dumped = Marshal.dump(e)
289
- dumped = nil if dumped.length > 64 * 1024
290
- rescue
291
- dumped = nil
292
- end
262
+ dumped = Marshal.dump(e)
263
+ dumped = nil if dumped.length > 64 * 1024
264
+ rescue
265
+ dumped = nil
266
+ end
293
267
 
294
- if dumped.nil?
295
- # couldn't dump the exception; create a copy with just
296
- # the message and the backtrace
297
- e2 = e.class.new(e.message)
298
- backtrace = e.backtrace
299
- # truncate excessively long backtraces
300
- if backtrace.length > 50
301
- backtrace = backtrace[0...25] + ['...'] + backtrace[-25..-1]
302
- end
303
- e2.set_backtrace(backtrace)
304
- e2.instance_variable_set(:@active_shards, e.instance_variable_get(:@active_shards))
305
- dumped = Marshal.dump(e2)
268
+ if dumped.nil?
269
+ # couldn't dump the exception; create a copy with just
270
+ # the message and the backtrace
271
+ e2 = e.class.new(e.message)
272
+ backtrace = e.backtrace
273
+ # truncate excessively long backtraces
274
+ if backtrace.length > 50
275
+ backtrace = backtrace[0...25] + ['...'] + backtrace[-25..-1]
306
276
  end
307
-
308
- exception_pipe.last.set_encoding(dumped.encoding)
309
- exception_pipe.last.write(dumped)
310
- exception_pipe.last.flush
311
- exception_pipe.last.close
312
- exit! 1
277
+ e2.set_backtrace(backtrace)
278
+ e2.instance_variable_set(:@active_shards, e.instance_variable_get(:@active_shards))
279
+ dumped = Marshal.dump(e2)
313
280
  end
314
- end)
315
- exception_pipe.last.close
316
- pids << pid
317
- io_in.close # don't care about writing to stdin
318
- out_fds << io_out
319
- err_fds << io_err
320
- pid_to_name_map[pid] = name
321
- fd_to_name_map[io_out] = name
322
- fd_to_name_map[io_err] = name
323
-
324
- while max_procs && pids.count >= max_procs
325
- while max_procs && out_fds.count >= max_procs
326
- # wait for output if we've hit the max_procs limit
327
- wait_for_output.call(out_fds, err_fds, fd_to_name_map)
328
- end
329
- # we've gotten all the output from one fd so wait for its child process to exit
330
- found_pid, status = Process.wait2
331
- pids.delete(found_pid)
332
- errors << pid_to_name_map[found_pid] if status.exitstatus != 0
281
+
282
+ exception_pipe.last.set_encoding(dumped.encoding)
283
+ exception_pipe.last.write(dumped)
284
+ exception_pipe.last.flush
285
+ exception_pipe.last.close
286
+ exit! 1
287
+ end
288
+ end)
289
+ exception_pipe.last.close
290
+ pids << pid
291
+ io_in.close # don't care about writing to stdin
292
+ out_fds << io_out
293
+ err_fds << io_err
294
+ pid_to_name_map[pid] = name
295
+ fd_to_name_map[io_out] = name
296
+ fd_to_name_map[io_err] = name
297
+
298
+ while pids.count >= parallel
299
+ while out_fds.count >= parallel
300
+ # wait for output if we've hit the parallel limit
301
+ wait_for_output.call(out_fds, err_fds, fd_to_name_map)
333
302
  end
303
+ # we've gotten all the output from one fd so wait for its child process to exit
304
+ found_pid, status = Process.wait2
305
+ pids.delete(found_pid)
306
+ errors << pid_to_name_map[found_pid] if status.exitstatus != 0
334
307
  end
335
308
  end
336
309
 
@@ -544,24 +517,6 @@ module Switchman
544
517
  shard || source_shard || Shard.current
545
518
  end
546
519
 
547
- # given the provided option, determines whether we need to (and whether
548
- # it's possible) to determine a reasonable default.
549
- def determine_max_procs(max_procs_input, parallel_input=2)
550
- max_procs = nil
551
- if max_procs_input
552
- max_procs = max_procs_input.to_i
553
- max_procs = nil if max_procs == 0
554
- else
555
- return 1 if parallel_input.nil? || parallel_input < 1
556
- cpus = Environment.cpu_count
557
- if cpus && cpus > 0
558
- max_procs = cpus * parallel_input
559
- end
560
- end
561
-
562
- return max_procs
563
- end
564
-
565
520
  private
566
521
  # in-process caching
567
522
  def cached_shards
@@ -38,11 +38,15 @@ module Switchman
38
38
  def define_method_global_attribute(attr_name)
39
39
  if sharded_column?(attr_name)
40
40
  generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
41
- def __temp__
41
+ def __temp_global_attribute__
42
+ raw_value = original_#{attr_name}
43
+ return nil if raw_value.nil?
44
+ return raw_value if raw_value > Shard::IDS_PER_SHARD
45
+
42
46
  Shard.global_id_for(original_#{attr_name}, shard)
43
47
  end
44
- alias_method 'global_#{attr_name}', :__temp__
45
- undef_method :__temp__
48
+ alias_method 'global_#{attr_name}', :__temp_global_attribute__
49
+ undef_method :__temp_global_attribute__
46
50
  RUBY
47
51
  else
48
52
  define_method_unsharded_column(attr_name, 'global')
@@ -52,11 +56,13 @@ module Switchman
52
56
  def define_method_local_attribute(attr_name)
53
57
  if sharded_column?(attr_name)
54
58
  generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
55
- def __temp__
56
- Shard.local_id_for(original_#{attr_name}).first
59
+ def __temp_local_attribute__
60
+ raw_value = original_#{attr_name}
61
+ return nil if raw_value.nil?
62
+ return raw_value % Shard::IDS_PER_SHARD
57
63
  end
58
- alias_method 'local_#{attr_name}', :__temp__
59
- undef_method :__temp__
64
+ alias_method 'local_#{attr_name}', :__temp_local_attribute__
65
+ undef_method :__temp_local_attribute__
60
66
  RUBY
61
67
  else
62
68
  define_method_unsharded_column(attr_name, 'local')
@@ -84,7 +90,7 @@ module Switchman
84
90
  def define_method_original_attribute(attr_name)
85
91
  if sharded_column?(attr_name)
86
92
  reflection = reflection_for_integer_attribute(attr_name)
87
- if attr_name == "id" && ::Rails.version >= '5.1.2'
93
+ if attr_name == "id"
88
94
  return if self.method_defined?(:original_id)
89
95
  owner = self
90
96
  else
@@ -94,18 +100,33 @@ module Switchman
94
100
  # rename the original method to original_
95
101
  alias_method 'original_#{attr_name}', '#{attr_name}'
96
102
  # and replace with one that transposes the id
97
- def __temp__
98
- Shard.relative_id_for(original_#{attr_name}, shard, Shard.current(#{shard_category_code_for_reflection(reflection)}))
103
+ def __temp_relative_attribute__
104
+ raw_value = original_#{attr_name}
105
+ return nil if raw_value.nil?
106
+
107
+ abs_raw_value = raw_value.abs
108
+ current_shard = Shard.current(#{shard_category_code_for_reflection(reflection)})
109
+ same_shard = shard == current_shard
110
+ return raw_value if same_shard && abs_raw_value < Shard::IDS_PER_SHARD
111
+
112
+ value_shard_id = abs_raw_value / Shard::IDS_PER_SHARD
113
+ # this is a stupid case when someone stuffed a global id for the current shard in instead
114
+ # of a local id
115
+ return raw_value % Shard::IDS_PER_SHARD if value_shard_id == current_shard.id
116
+ return raw_value if !same_shard && abs_raw_value > Shard::IDS_PER_SHARD
117
+ return shard.global_id_for(raw_value) if !same_shard && abs_raw_value < Shard::IDS_PER_SHARD
118
+
119
+ Shard.relative_id_for(raw_value, shard, current_shard)
99
120
  end
100
- alias_method '#{attr_name}', :__temp__
101
- undef_method :__temp__
121
+ alias_method '#{attr_name}', :__temp_relative_attribute__
122
+ undef_method :__temp_relative_attribute__
102
123
 
103
124
  alias_method 'original_#{attr_name}=', '#{attr_name}='
104
- def __temp__(new_value)
125
+ def __temp_relative_attribute_assignment__(new_value)
105
126
  self.original_#{attr_name} = Shard.relative_id_for(new_value, Shard.current(#{shard_category_code_for_reflection(reflection)}), shard)
106
127
  end
107
- alias_method '#{attr_name}=', :__temp__
108
- undef_method :__temp__
128
+ alias_method '#{attr_name}=', :__temp_relative_attribute_assignment__
129
+ undef_method :__temp_relative_attribute_assignment__
109
130
  RUBY
110
131
  else
111
132
  define_method_unsharded_column(attr_name, 'global')
@@ -115,11 +136,11 @@ module Switchman
115
136
  def define_method_unsharded_column(attr_name, prefix)
116
137
  return if columns_hash["#{prefix}_#{attr_name}"]
117
138
  generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1
118
- def __temp__
139
+ def __temp_unsharded_attribute__
119
140
  raise NoMethodError, "undefined method `#{prefix}_#{attr_name}'; are you missing an association?"
120
141
  end
121
- alias_method '#{prefix}_#{attr_name}', :__temp__
122
- undef_method :__temp__
142
+ alias_method '#{prefix}_#{attr_name}', :__temp_unsharded_attribute__
143
+ undef_method :__temp_unsharded_attribute__
123
144
  RUBY
124
145
  end
125
146
  end
@@ -80,17 +80,17 @@ module Switchman
80
80
  end
81
81
  end
82
82
 
83
- def self.included(klass)
84
- klass.extend(ClassMethods)
85
- klass.set_callback(:initialize, :before) do
86
- unless @shard
87
- if self.class.sharded_primary_key?
88
- @shard = Shard.shard_for(self[self.class.primary_key], Shard.current(self.class.shard_category))
89
- else
90
- @shard = Shard.current(self.class.shard_category)
91
- end
92
- end
83
+ def self.prepended(klass)
84
+ klass.singleton_class.prepend(ClassMethods)
85
+ end
86
+
87
+ def _run_initialize_callbacks
88
+ @shard ||= if self.class.sharded_primary_key?
89
+ Shard.shard_for(self[self.class.primary_key], Shard.current(self.class.shard_category))
90
+ else
91
+ Shard.current(self.class.shard_category)
93
92
  end
93
+ super
94
94
  end
95
95
 
96
96
  def shard
@@ -158,7 +158,7 @@ module Switchman
158
158
  end
159
159
 
160
160
  def update_columns(*)
161
- db = Shard.current(self.class.shard_category).database_server
161
+ db = shard.database_server
162
162
  if ::GuardRail.environment != db.guard_rail_environment
163
163
  return db.unguard { super }
164
164
  else
@@ -118,7 +118,7 @@ module Switchman
118
118
  next if k == spec_name
119
119
 
120
120
  v = owner_to_pool[k]
121
- owner_to_pool.delete(k) if v.is_a?(ConnectionPoolProxy) && v.spec.name == spec_name
121
+ owner_to_pool.delete(k) if v.is_a?(ConnectionPoolProxy) && v.default_pool.spec.name == spec_name
122
122
  end
123
123
 
124
124
  # unwrap the pool from inside a ConnectionPoolProxy
@@ -75,7 +75,9 @@ module Switchman
75
75
  end
76
76
  @available.clear
77
77
  @connections.each do |conn|
78
- @available.add conn
78
+ # we do not want to be introducing leased
79
+ # connections into the available queue
80
+ @available.add(conn) unless conn.in_use?
79
81
  end
80
82
  end
81
83
  end
@@ -20,10 +20,7 @@ module Switchman
20
20
  shard = " [#{shard[:database_server_id]}:#{shard[:id]} #{shard[:env]}]" if shard
21
21
 
22
22
  unless (payload[:binds] || []).empty?
23
- use_old_format = (::Rails.version < '5.1.5')
24
- args = use_old_format ?
25
- [payload[:binds], payload[:type_casted_binds]] :
26
- [payload[:type_casted_binds]]
23
+ args = [payload[:type_casted_binds]]
27
24
  casted_params = type_casted_binds(*args)
28
25
  binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
29
26
  render_bind(attr, value)
@@ -30,10 +30,13 @@ module Switchman
30
30
  end
31
31
 
32
32
  module Migrator
33
- # significant change: hash shard id, not database name
33
+ # significant change: just return MIGRATOR_SALT directly
34
+ # especially if you're going through pgbouncer, the database
35
+ # name you're accessing may not be consistent. it is NOT allowed
36
+ # to run migrations against multiple shards in the same database
37
+ # concurrently
34
38
  def generate_migrator_advisory_lock_id
35
- shard_name_hash = Zlib.crc32(Shard.current.name)
36
- ::ActiveRecord::Migrator::MIGRATOR_SALT * shard_name_hash
39
+ ::ActiveRecord::Migrator::MIGRATOR_SALT
37
40
  end
38
41
 
39
42
  if ::Rails.version >= '6.0'
@@ -13,6 +13,15 @@ module Switchman
13
13
  shard.activate(self.class.shard_category) { super }
14
14
  end
15
15
  end
16
+
17
+ def delete
18
+ db = shard.database_server
19
+ if ::GuardRail.environment != db.guard_rail_environment
20
+ return db.unguard { super }
21
+ else
22
+ super
23
+ end
24
+ end
16
25
  end
17
26
  end
18
- end
27
+ end
@@ -102,7 +102,7 @@ module Switchman
102
102
  WHERE i.relkind = 'i'
103
103
  AND d.indisprimary = 'f'
104
104
  AND t.relname = '#{table_name}'
105
- AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = '#{shard.name}' )
105
+ AND t.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname = '#{shard.name}' )
106
106
  ORDER BY i.relname
107
107
  SQL
108
108
 
@@ -19,7 +19,7 @@ module Switchman
19
19
  connection_id: object_id,
20
20
  cached: true
21
21
  }
22
- args[:type_casted_binds] = -> { type_casted_binds(binds) } if ::Rails.version >= '5.1.5'
22
+ args[:type_casted_binds] = -> { type_casted_binds(binds) }
23
23
  ::ActiveSupport::Notifications.instrument(
24
24
  "sql.active_record",
25
25
  args
@@ -78,6 +78,10 @@ module Switchman
78
78
  end
79
79
  end
80
80
 
81
+ def or(other)
82
+ super(other.shard(self.primary_shard))
83
+ end
84
+
81
85
  private
82
86
 
83
87
  if ::Rails.version >= '5.2'
@@ -258,6 +262,25 @@ module Switchman
258
262
  end)
259
263
  end
260
264
 
265
+ if predicate.is_a?(::Arel::Nodes::Grouping)
266
+ next predicate unless predicate.expr.is_a?(::Arel::Nodes::Or)
267
+
268
+ or_expr = predicate.expr
269
+ left_node = or_expr.left
270
+ right_node = or_expr.right
271
+ new_left_predicates, binds = transpose_predicates([left_node], source_shard, target_shard,
272
+ remove_nonlocal_primary_keys,
273
+ binds: binds,
274
+ dup_binds_on_mutation: dup_binds_on_mutation)
275
+ new_right_predicates, binds = transpose_predicates([right_node], source_shard, target_shard,
276
+ remove_nonlocal_primary_keys,
277
+ binds: binds,
278
+ dup_binds_on_mutation: dup_binds_on_mutation)
279
+
280
+ next predicate if new_left_predicates[0] == left_node && new_right_predicates[0] == right_node
281
+ next ::Arel::Nodes::Grouping.new ::Arel::Nodes::Or.new(new_left_predicates[0], new_right_predicates[0])
282
+ end
283
+
261
284
  next predicate unless predicate.is_a?(::Arel::Nodes::Binary)
262
285
  next predicate unless predicate.left.is_a?(::Arel::Attributes::Attribute)
263
286
  relation, column = relation_and_column(predicate.left)
@@ -154,7 +154,7 @@ module Switchman
154
154
  end
155
155
  end
156
156
  spec = ::ActiveRecord::ConnectionAdapters::ConnectionSpecification.new(
157
- category,
157
+ default_pool.spec.name,
158
158
  config,
159
159
  "#{config[:adapter]}_connection"
160
160
  )
@@ -95,7 +95,7 @@ module Switchman
95
95
 
96
96
  ::StandardError.include(StandardError)
97
97
 
98
- include ActiveRecord::Base
98
+ prepend ActiveRecord::Base
99
99
  include ActiveRecord::AttributeMethods
100
100
  include ActiveRecord::Persistence
101
101
  singleton_class.prepend ActiveRecord::ModelSchema::ClassMethods
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- VERSION = "2.1.0"
4
+ VERSION = "2.2.3"
5
5
  end
@@ -46,7 +46,8 @@ module Switchman
46
46
  end
47
47
 
48
48
  def self.options
49
- { parallel: ENV['PARALLEL'].to_i, max_procs: ENV['MAX_PARALLEL_PROCS'] }
49
+ # we still pass through both of these options for back-compat purposes
50
+ { parallel: ENV['PARALLEL']&.to_i, max_procs: ENV['MAX_PARALLEL_PROCS']&.to_i }
50
51
  end
51
52
 
52
53
  # categories - an array or proc, to activate as the current shard during the
@@ -89,7 +90,7 @@ module Switchman
89
90
  nil
90
91
  end
91
92
  rescue => e
92
- puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel] != 0
93
+ puts "Exception from #{e.current_shard.id}: #{e.current_shard.description}" if options[:parallel].to_i != 0
93
94
  raise
94
95
  end
95
96
  end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: switchman
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cody Cutrer
8
8
  - James Williams
9
9
  - Jacob Fugal
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2021-07-12 00:00:00.000000000 Z
13
+ date: 2022-03-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: railties
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: '5.1'
21
+ version: '5.2'
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
24
  version: '6.1'
@@ -28,7 +28,7 @@ dependencies:
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: '5.1'
31
+ version: '5.2'
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '6.1'
@@ -38,7 +38,7 @@ dependencies:
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '5.1'
41
+ version: '5.2'
42
42
  - - "<"
43
43
  - !ruby/object:Gem::Version
44
44
  version: '6.1'
@@ -48,7 +48,7 @@ dependencies:
48
48
  requirements:
49
49
  - - ">="
50
50
  - !ruby/object:Gem::Version
51
- version: '5.1'
51
+ version: '5.2'
52
52
  - - "<"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '6.1'
@@ -257,7 +257,7 @@ homepage: http://www.instructure.com/
257
257
  licenses:
258
258
  - MIT
259
259
  metadata: {}
260
- post_install_message:
260
+ post_install_message:
261
261
  rdoc_options: []
262
262
  require_paths:
263
263
  - lib
@@ -265,15 +265,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
265
265
  requirements:
266
266
  - - ">="
267
267
  - !ruby/object:Gem::Version
268
- version: '2.5'
268
+ version: '2.6'
269
269
  required_rubygems_version: !ruby/object:Gem::Requirement
270
270
  requirements:
271
271
  - - ">="
272
272
  - !ruby/object:Gem::Version
273
273
  version: '0'
274
274
  requirements: []
275
- rubygems_version: 3.2.15
276
- signing_key:
275
+ rubygems_version: 3.1.4
276
+ signing_key:
277
277
  specification_version: 4
278
278
  summary: Rails sharding magic
279
279
  test_files: []