switchman 2.1.0 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
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: []