switchman 3.6.3 → 3.6.5

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: 8a34057337ce5a3a1ded4a6964c52d777c561b44af92c15bb50d3f4a83f92cdc
4
- data.tar.gz: d4c840584fa965c7e46ac378a17135e024f99c7e9ee30f1448a75e83721860ad
3
+ metadata.gz: 7f9407ddbab463ffaa11b358a6591186d512f7558dde95713bf54f584a0fd362
4
+ data.tar.gz: a356c5a51ffad024b5c23ab69f5b32bbfa95785f8cbec7c80f0d0ef0eb0f4996
5
5
  SHA512:
6
- metadata.gz: 3dc282c71808ca9bbac544773d8025d0e46fa0777de110f5c1b6957622022fdf43e7d5b148abc07b6176b5043008af85dc49bd58ca2e4a6960a42954bbddf49b
7
- data.tar.gz: 7455c67b0d20e635295f5ce3f6d839019f00bae14d2f03ded1e0a0572c22e270e6793bd113f0fc9644621e5c62ae6c7ae546ec92deadc1d7a7b8d363cb34bef1
6
+ metadata.gz: b0470870a20eb63d03cf46efa57b6db2dc9b3f14701491293b298261f71e7db93cb82d7c27cb9b36a6ea36f6de1d97daf3ec56cd0fb6e3d1595daad65044f1f2
7
+ data.tar.gz: c28da8999f5660e01486ac4c28dfddb1b254422d7f51f29156bcd97ec6d774bcdcc0c2ef4ffbd7de4f959adaedd6005dc3e9535bc317f7312620c7f8d88236a8
@@ -153,8 +153,13 @@ module Switchman
153
153
 
154
154
  def self.prepended(klass)
155
155
  klass.singleton_class.prepend(ClassMethods)
156
- klass.scope :non_shadow, ->(key = primary_key) { where(key => 0..Shard::IDS_PER_SHARD) }
157
- klass.scope :shadow, ->(key = primary_key) { where(key => Shard::IDS_PER_SHARD..) }
156
+ klass.scope :non_shadow, lambda { |key = primary_key|
157
+ where(key => (QueryMethods::NonTransposingValue.new(0)..
158
+ QueryMethods::NonTransposingValue.new(Shard::IDS_PER_SHARD)))
159
+ }
160
+ klass.scope :shadow, lambda { |key = primary_key|
161
+ where(key => QueryMethods::NonTransposingValue.new(Shard::IDS_PER_SHARD)..)
162
+ }
158
163
  end
159
164
 
160
165
  def _run_initialize_callbacks
@@ -3,6 +3,19 @@
3
3
  module Switchman
4
4
  module ActiveRecord
5
5
  module QueryMethods
6
+ # Use this class to prevent a value from getting transposed across shards
7
+ class NonTransposingValue < SimpleDelegator
8
+ def class
9
+ __getobj__.class
10
+ end
11
+
12
+ def is_a?(other)
13
+ return true if other == NonTransposingValue
14
+
15
+ __getobj__.is_a?(other)
16
+ end
17
+ end
18
+
6
19
  # shard_value is one of:
7
20
  # A shard
8
21
  # An array or relation of shards
@@ -398,7 +411,9 @@ module Switchman
398
411
  end
399
412
 
400
413
  def transpose_predicate_value(value, current_shard, target_shard, attribute_type)
401
- if value.is_a?(::ActiveRecord::StatementCache::Substitute)
414
+ if value.is_a?(NonTransposingValue)
415
+ value
416
+ elsif value.is_a?(::ActiveRecord::StatementCache::Substitute)
402
417
  value.sharded = true # mark for transposition later
403
418
  value.primary = true if attribute_type == :primary
404
419
  value
@@ -50,16 +50,16 @@ module Switchman
50
50
  end
51
51
  end
52
52
 
53
- class PrefixingIO
53
+ class TransformingIO
54
54
  delegate_missing_to :@original_io
55
55
 
56
- def initialize(prefix, original_io)
57
- @prefix = prefix
56
+ def initialize(transformer, original_io)
57
+ @transformer = transformer
58
58
  @original_io = original_io
59
59
  end
60
60
 
61
61
  def puts(*args)
62
- args.flatten.each { |arg| @original_io.puts "#{@prefix}: #{arg}" }
62
+ args.flatten.each { |arg| @original_io.puts @transformer.call(arg) }
63
63
  end
64
64
  end
65
65
  end
@@ -165,7 +165,7 @@ module Switchman
165
165
  # forking.
166
166
  # exception: - :ignore, :raise, :defer (wait until the end and raise the first
167
167
  # error), or a proc
168
- # output: - :simple, :decorated (with database_server_id:shard_name)
168
+ # output: - :simple, :decorated (with database_server_id:shard_name), custom lambda transformer
169
169
  def with_each_shard(*args, parallel: false, exception: :raise, output: :simple)
170
170
  raise ArgumentError, "wrong number of arguments (#{args.length} for 0...2)" if args.length > 2
171
171
 
@@ -181,6 +181,13 @@ module Switchman
181
181
  scope, classes = args
182
182
  end
183
183
 
184
+ output = if output == :decorated
185
+ ->(arg) { "#{Shard.current.description}: #{arg}" }
186
+ elsif output == :simple
187
+ nil
188
+ else
189
+ output
190
+ end
184
191
  parallel = [Environment.cpu_count || 2, 2].min if parallel == true
185
192
  parallel = 0 if parallel == false || parallel.nil?
186
193
 
@@ -224,7 +231,10 @@ module Switchman
224
231
  new_title = [short_parent_name, name].join(" ")
225
232
  Process.setproctitle(new_title)
226
233
  Switchman.config[:on_fork_proc]&.call
227
- with_each_shard(subscope, classes, exception: exception, output: :decorated) do
234
+ with_each_shard(subscope,
235
+ classes,
236
+ exception: exception,
237
+ output: output || :decorated) do
228
238
  last_description = Shard.current.description
229
239
  Parallel::ResultWrapper.new(yield)
230
240
  end
@@ -258,9 +268,9 @@ module Switchman
258
268
  next unless shard.database_server
259
269
 
260
270
  shard.activate(*classes) do
261
- if output == :decorated
262
- $stdout = Parallel::PrefixingIO.new(shard.description, $stdout)
263
- $stderr = Parallel::PrefixingIO.new(shard.description, $stderr)
271
+ if output
272
+ $stdout = Parallel::TransformingIO.new(output, $stdout)
273
+ $stderr = Parallel::TransformingIO.new(output, $stderr)
264
274
  end
265
275
 
266
276
  result.concat Array.wrap(yield)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Switchman
4
- VERSION = "3.6.3"
4
+ VERSION = "3.6.5"
5
5
  end
@@ -71,12 +71,13 @@ module Switchman
71
71
  end
72
72
 
73
73
  def self.options
74
- { parallel: ENV["PARALLEL"].to_i }
74
+ { exception: (ENV["FAIL_FAST"] == "0") ? :defer : :raise, parallel: ENV["PARALLEL"].to_i }
75
75
  end
76
76
 
77
77
  # classes - an array or proc, to activate as the current shard during the
78
78
  # task.
79
79
  def self.shardify_task(task_name, classes: [::ActiveRecord::Base])
80
+ log_format = ENV.fetch("LOG_FORMAT", nil)
80
81
  old_task = ::Rake::Task[task_name]
81
82
  old_actions = old_task.actions.dup
82
83
  old_task.actions.clear
@@ -90,14 +91,56 @@ module Switchman
90
91
  ::GuardRail.activate(:deploy) do
91
92
  Shard.default.database_server.unguard do
92
93
  classes = classes.call if classes.respond_to?(:call)
93
- Shard.with_each_shard(scope, classes, **options) do
94
+
95
+ # We don't want the shard status messages to be wrapped using a custom log transfomer
96
+ original_stderr = $stderr
97
+ original_stdout = $stdout
98
+ output = if log_format == "json"
99
+ lambda { |msg|
100
+ JSON.dump(shard: Shard.current.id,
101
+ database_server: Shard.current.database_server.id,
102
+ type: "log",
103
+ message: msg)
104
+ }
105
+ else
106
+ nil
107
+ end
108
+ Shard.with_each_shard(scope, classes, output: output, **options) do
94
109
  shard = Shard.current
95
- puts "#{shard.id}: #{shard.description}"
110
+
111
+ if log_format == "json"
112
+ original_stdout.puts JSON.dump(
113
+ shard: shard.id,
114
+ database_server: shard.database_server.id,
115
+ type: "started"
116
+ )
117
+ else
118
+ original_stdout.puts "#{shard.id}: #{shard.description}"
119
+ end
96
120
 
97
121
  shard.database_server.unguard do
98
122
  old_actions.each { |action| action.call(*task_args) }
99
123
  end
124
+
125
+ if log_format == "json"
126
+ original_stdout.puts JSON.dump(
127
+ shard: shard.id,
128
+ database_server: shard.database_server.id,
129
+ type: "completed"
130
+ )
131
+ end
100
132
  nil
133
+ rescue => e
134
+ if log_format == "json"
135
+ original_stderr.puts JSON.dump(
136
+ shard: shard.id,
137
+ database_server: shard.database_server.id,
138
+ type: "failed",
139
+ message: e.full_message
140
+ )
141
+ end
142
+
143
+ raise
101
144
  end
102
145
  rescue => e
103
146
  if options[:parallel] != 0
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.6.3
4
+ version: 3.6.5
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: 2024-04-25 00:00:00.000000000 Z
13
+ date: 2024-06-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord