ci-queue 0.96.0 → 0.98.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/Gemfile.lock +1 -1
- data/README.md +76 -1
- data/lib/ci/queue/circuit_breaker.rb +36 -0
- data/lib/ci/queue/common.rb +4 -0
- data/lib/ci/queue/configuration.rb +8 -1
- data/lib/ci/queue/version.rb +1 -1
- data/lib/minitest/queue/runner.rb +9 -0
- data/lib/minitest/queue/test_data.rb +20 -1
- data/lib/minitest/queue.rb +84 -1
- data/lib/rspec/queue.rb +21 -9
- 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: 020b8bf0b6887aa814e3f6b310bc62888e9a5e0af94c6ed652efc0af2b947ef7
|
|
4
|
+
data.tar.gz: 11e86bbe7b3e6bacfe96b84ae131c40222fb61a1afa9788f953c3a85db02d751
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b02b9a927e82321c3792c5a479487ef2a80e1093e23d4614e1e3b9191b9a5b5f9691cbdc78bd2a2a566e97dcbcf6231c3d9df19521bc2408099b6e905c38ecfa
|
|
7
|
+
data.tar.gz: 39cbdb4ef28553b81373f5836a8267b1919815fcab5959893bf002a307b7341e6337e045b00dd8a06e4c93dba2a1b3bd05ca9b96672292b5e25b8f50cc507fbf
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -36,7 +36,7 @@ Assuming you use one of the supported CI providers, the command can be as simple
|
|
|
36
36
|
minitest-queue --queue redis://example.com run -Itest test/**/*_test.rb
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Additionally you can configure the requeue settings (see main README) with `--max-requeues` and `--requeue-tolerance`.
|
|
39
|
+
Additionally you can configure the requeue settings (see main README) with `--max-requeues` and `--requeue-tolerance`. Worker-health circuit breakers are available through `--max-consecutive-failures` and `--max-consecutive-requeues`.
|
|
40
40
|
|
|
41
41
|
#### Lazy loading (opt-in)
|
|
42
42
|
|
|
@@ -138,6 +138,57 @@ The runner also comes with a tool to investigate leaky tests:
|
|
|
138
138
|
minitest-queue --queue path/to/test_order.log --failing-test 'SomeTest#test_something' bisect -Itest test/**/*_test.rb
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
#### Parallel worker metadata
|
|
142
|
+
|
|
143
|
+
Each result is stamped, as it is recorded in the process that ran the test, with:
|
|
144
|
+
|
|
145
|
+
- `parallel_worker_pid`: the pid of the process that ran the test.
|
|
146
|
+
- `parallel_worker_test_index`: a 0-based monotonic counter of results recorded by that process (requeued executions get their own index). Restarts at 0 in each forked process.
|
|
147
|
+
- `parallel_worker_id`: an identifier injected by the embedding environment (e.g. a Rails parallel-testing worker number); `nil` when not applicable.
|
|
148
|
+
|
|
149
|
+
All three fields are included (nil-safe) in `log/test_data.json` emitted by the test data reporter, making per-worker-process execution order reconstructable downstream (`PARTITION BY parallel_worker_id, parallel_worker_pid ORDER BY parallel_worker_test_index`).
|
|
150
|
+
|
|
151
|
+
The worker id can be provided either programmatically or via the environment:
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
Minitest::Queue.parallel_worker_id = 3
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Variable | Description |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `CI_QUEUE_PARALLEL_WORKER_ID=N` | Sets `parallel_worker_id` for results produced by this process. Read once per process; the setter takes precedence. |
|
|
160
|
+
|
|
161
|
+
Stamping is first-writer-wins. When ci-queue runs tests in-process (the normal
|
|
162
|
+
`minitest-queue` flow), results are stamped automatically as they are recorded.
|
|
163
|
+
Embedding environments that run tests in forked workers and transport results to
|
|
164
|
+
another process (e.g. over DRb to a central reporting server) must stamp in the
|
|
165
|
+
worker **before** sending:
|
|
166
|
+
|
|
167
|
+
```ruby
|
|
168
|
+
# in the forked worker, after running the test and before the DRb send
|
|
169
|
+
Minitest::Queue.stamp_parallel_worker_metadata(result)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Otherwise the automatic stamp during reporting would capture the reporting
|
|
173
|
+
process's pid and an arrival-order index interleaved across workers. Pre-stamped
|
|
174
|
+
results pass through reporting untouched.
|
|
175
|
+
|
|
176
|
+
Notes:
|
|
177
|
+
|
|
178
|
+
- `parallel_worker_id` identifies a forked test process *inside* one queue worker.
|
|
179
|
+
It is unrelated to ci-queue's own `--worker` / `CI::Queue::Configuration#worker_id`,
|
|
180
|
+
which identifies the whole queue worker (typically one CI job).
|
|
181
|
+
- The payload intentionally carries no build/job identity — like every other field
|
|
182
|
+
in `log/test_data.json`, scoping to a build/job (e.g. a `job_id` column making
|
|
183
|
+
`(job_id, parallel_worker_id, parallel_worker_pid)` unique across a build) is
|
|
184
|
+
expected to be attached by whatever pipeline ingests the file.
|
|
185
|
+
- Stamping is mutex-guarded, so indexes are unique and gap-free even when results
|
|
186
|
+
are recorded from multiple threads. However, per-worker order reconstruction is
|
|
187
|
+
only meaningful with process-based (forked) workers: under thread-based
|
|
188
|
+
parallelization all threads share one `(parallel_worker_id, parallel_worker_pid)`
|
|
189
|
+
partition and the index reflects record order across threads.
|
|
190
|
+
- This applies to minitest-queue only; rspec-queue does not emit these fields.
|
|
191
|
+
|
|
141
192
|
### RSpec [DEPRECATED]
|
|
142
193
|
|
|
143
194
|
The rspec-queue runner is deprecated. The minitest-queue runner continues to be supported and is actively being improved. At Shopify, we strongly recommend that new projects set up their test suite using Minitest rather than RSpec.
|
|
@@ -158,6 +209,30 @@ rspec-queue --queue redis://example.com --timeout 600 --report
|
|
|
158
209
|
|
|
159
210
|
Because of how `ci-queue` executes the examples, `before(:all)` and `after(:all)` hooks are not supported. `rspec-queue` will explicitly reject them.
|
|
160
211
|
|
|
212
|
+
### Worker circuit breakers
|
|
213
|
+
|
|
214
|
+
Both runners support two independent, disabled-by-default circuit breakers:
|
|
215
|
+
|
|
216
|
+
- `--max-consecutive-failures MAX` stops a worker after `MAX` consecutive final test failures.
|
|
217
|
+
- `--max-consecutive-requeues MAX` stops a worker after `MAX` consecutive failures were accepted for requeueing.
|
|
218
|
+
|
|
219
|
+
The requeue count is local to each worker and resets whenever that worker produces any non-requeued result, including a pass, skip, ignored flaky result, or final failure. An accepted requeue neither increments nor resets the consecutive-final-failure count. Requeue attempts rejected because of an ownership race or an exhausted retry budget follow the final-failure path and do not increment the requeue count.
|
|
220
|
+
|
|
221
|
+
For example:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
minitest-queue --max-consecutive-requeues 10 --queue redis://example.com run test/**/*_test.rb
|
|
225
|
+
rspec-queue --max-consecutive-requeues 10 --queue redis://example.com
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
The breaker can also be configured programmatically:
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
CI::Queue::Configuration.new(max_consecutive_requeues: 10)
|
|
232
|
+
# or
|
|
233
|
+
config.max_consecutive_requeues = 10
|
|
234
|
+
```
|
|
235
|
+
|
|
161
236
|
## Releasing a New Version
|
|
162
237
|
|
|
163
238
|
After merging changes to `main`, follow these steps to release and propagate the update:
|
|
@@ -8,6 +8,9 @@ module CI
|
|
|
8
8
|
def report_failure!
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
def report_requeue!
|
|
12
|
+
end
|
|
13
|
+
|
|
11
14
|
def report_success!
|
|
12
15
|
end
|
|
13
16
|
|
|
@@ -32,6 +35,9 @@ module CI
|
|
|
32
35
|
def report_failure!
|
|
33
36
|
end
|
|
34
37
|
|
|
38
|
+
def report_requeue!
|
|
39
|
+
end
|
|
40
|
+
|
|
35
41
|
def report_success!
|
|
36
42
|
end
|
|
37
43
|
|
|
@@ -60,6 +66,9 @@ module CI
|
|
|
60
66
|
@consecutive_failures += 1
|
|
61
67
|
end
|
|
62
68
|
|
|
69
|
+
def report_requeue!
|
|
70
|
+
end
|
|
71
|
+
|
|
63
72
|
def report_success!
|
|
64
73
|
@consecutive_failures = 0
|
|
65
74
|
end
|
|
@@ -72,6 +81,33 @@ module CI
|
|
|
72
81
|
'This worker is exiting early because it encountered too many consecutive test failures, probably because of some corrupted state.'
|
|
73
82
|
end
|
|
74
83
|
end
|
|
84
|
+
|
|
85
|
+
class MaxConsecutiveRequeues
|
|
86
|
+
def initialize(max_consecutive_requeues:)
|
|
87
|
+
@max = max_consecutive_requeues
|
|
88
|
+
@consecutive_requeues = 0
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def report_failure!
|
|
92
|
+
@consecutive_requeues = 0
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def report_requeue!
|
|
96
|
+
@consecutive_requeues += 1
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def report_success!
|
|
100
|
+
@consecutive_requeues = 0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def open?
|
|
104
|
+
@consecutive_requeues >= @max
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def message
|
|
108
|
+
'This worker is exiting early because it requeued too many consecutive tests, probably because of some corrupted state.'
|
|
109
|
+
end
|
|
110
|
+
end
|
|
75
111
|
end
|
|
76
112
|
end
|
|
77
113
|
end
|
data/lib/ci/queue/common.rb
CHANGED
|
@@ -55,7 +55,7 @@ module CI
|
|
|
55
55
|
def initialize(
|
|
56
56
|
timeout: 30, build_id: nil, worker_id: nil, max_requeues: 0, requeue_tolerance: 0,
|
|
57
57
|
namespace: nil, seed: nil, flaky_tests: [], statsd_endpoint: nil, max_consecutive_failures: nil,
|
|
58
|
-
grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
|
|
58
|
+
max_consecutive_requeues: nil, grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
|
|
59
59
|
max_test_duration_percentile: 0.5, track_test_duration: false, max_test_failed: nil,
|
|
60
60
|
queue_init_timeout: nil, redis_ttl: 8 * 60 * 60, report_timeout: nil, inactive_workers_timeout: nil,
|
|
61
61
|
export_flaky_tests_file: nil, warnings_file: nil, debug_log: nil, max_missed_heartbeat_seconds: nil, heartbeat_max_test_duration: nil,
|
|
@@ -79,6 +79,7 @@ module CI
|
|
|
79
79
|
@track_test_duration = track_test_duration
|
|
80
80
|
@worker_id = worker_id
|
|
81
81
|
self.max_consecutive_failures = max_consecutive_failures
|
|
82
|
+
self.max_consecutive_requeues = max_consecutive_requeues
|
|
82
83
|
self.max_duration = max_duration
|
|
83
84
|
@redis_ttl = redis_ttl
|
|
84
85
|
@report_timeout = report_timeout
|
|
@@ -165,6 +166,12 @@ module CI
|
|
|
165
166
|
end
|
|
166
167
|
end
|
|
167
168
|
|
|
169
|
+
def max_consecutive_requeues=(max)
|
|
170
|
+
if max
|
|
171
|
+
@circuit_breakers << CircuitBreaker::MaxConsecutiveRequeues.new(max_consecutive_requeues: max)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
168
175
|
def max_duration=(duration)
|
|
169
176
|
if duration
|
|
170
177
|
@circuit_breakers << CircuitBreaker::Timeout.new(duration: duration)
|
data/lib/ci/queue/version.rb
CHANGED
|
@@ -692,6 +692,15 @@ module Minitest
|
|
|
692
692
|
queue_config.max_consecutive_failures = max
|
|
693
693
|
end
|
|
694
694
|
|
|
695
|
+
help = <<~EOS
|
|
696
|
+
Defines after how many consecutive accepted requeues the worker will be considered unhealthy and stop reserving tests.
|
|
697
|
+
Defaults to disabled.
|
|
698
|
+
EOS
|
|
699
|
+
opts.separator ""
|
|
700
|
+
opts.on('--max-consecutive-requeues MAX', Integer, help) do |max|
|
|
701
|
+
queue_config.max_consecutive_requeues = max
|
|
702
|
+
end
|
|
703
|
+
|
|
695
704
|
help = <<~EOS
|
|
696
705
|
Must set this option in report and report_grind command if you set --max-test-duration in the report_grind
|
|
697
706
|
EOS
|
|
@@ -49,7 +49,7 @@ module Minitest
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def test_duration
|
|
52
|
-
@test.time
|
|
52
|
+
@test.time || 0.0
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def test_start_timestamp
|
|
@@ -73,6 +73,22 @@ module Minitest
|
|
|
73
73
|
@test.source_location.last
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
# The parallel_worker_* fields are stamped by
|
|
77
|
+
# Minitest::Queue.stamp_parallel_worker_metadata in the worker process
|
|
78
|
+
# that ran the test. They are nil for embedders that don't produce
|
|
79
|
+
# them (results lacking the accessors, or no worker id configured).
|
|
80
|
+
def parallel_worker_id
|
|
81
|
+
@test.parallel_worker_id if @test.respond_to?(:parallel_worker_id)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def parallel_worker_test_index
|
|
85
|
+
@test.parallel_worker_test_index if @test.respond_to?(:parallel_worker_test_index)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parallel_worker_pid
|
|
89
|
+
@test.parallel_worker_pid if @test.respond_to?(:parallel_worker_pid)
|
|
90
|
+
end
|
|
91
|
+
|
|
76
92
|
# Error class only considers failures wheras the other error fields also consider skips
|
|
77
93
|
def error_class
|
|
78
94
|
return nil unless @test.failure
|
|
@@ -119,6 +135,9 @@ module Minitest
|
|
|
119
135
|
test_finish_timestamp: test_finish_timestamp,
|
|
120
136
|
test_file_path: test_file_path,
|
|
121
137
|
test_file_line_number: test_file_line_number,
|
|
138
|
+
parallel_worker_id: parallel_worker_id,
|
|
139
|
+
parallel_worker_test_index: parallel_worker_test_index,
|
|
140
|
+
parallel_worker_pid: parallel_worker_pid,
|
|
122
141
|
error_class: error_class,
|
|
123
142
|
error_message: error_message,
|
|
124
143
|
error_file_path: error_file_path,
|
data/lib/minitest/queue.rb
CHANGED
|
@@ -111,10 +111,22 @@ module Minitest
|
|
|
111
111
|
attr_accessor :queue_id, :queue_entry
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
+
# Per-worker-process execution metadata, stamped on each result in the
|
|
115
|
+
# process that ran the test (before any DRb send in embedding
|
|
116
|
+
# environments), so that per-process execution order is reconstructable
|
|
117
|
+
# downstream: PARTITION BY parallel_worker_id, parallel_worker_pid
|
|
118
|
+
# ORDER BY parallel_worker_test_index.
|
|
119
|
+
module ParallelWorkerMetadata
|
|
120
|
+
attr_accessor :parallel_worker_id, :parallel_worker_test_index, :parallel_worker_pid
|
|
121
|
+
end
|
|
122
|
+
|
|
114
123
|
module Queue
|
|
115
124
|
extend ::CI::Queue::OutputHelpers
|
|
116
125
|
attr_writer :run_command_formatter, :project_root
|
|
117
126
|
|
|
127
|
+
PARALLEL_WORKER_METADATA_MUTEX = Mutex.new
|
|
128
|
+
private_constant :PARALLEL_WORKER_METADATA_MUTEX
|
|
129
|
+
|
|
118
130
|
def run_command_formatter
|
|
119
131
|
@run_command_formatter ||= if defined?(Rails) && defined?(Rails::TestUnitRailtie)
|
|
120
132
|
RAILS_RUN_COMMAND_FORMATTER
|
|
@@ -155,6 +167,60 @@ module Minitest
|
|
|
155
167
|
end
|
|
156
168
|
|
|
157
169
|
class << self
|
|
170
|
+
# Identifies which parallel worker this process is (e.g. Rails'
|
|
171
|
+
# parallel testing worker number). Injected by the embedding
|
|
172
|
+
# environment via this setter or the CI_QUEUE_PARALLEL_WORKER_ID
|
|
173
|
+
# environment variable; nil when not applicable.
|
|
174
|
+
attr_writer :parallel_worker_id
|
|
175
|
+
|
|
176
|
+
def parallel_worker_id
|
|
177
|
+
return @parallel_worker_id if @parallel_worker_id
|
|
178
|
+
|
|
179
|
+
# Memoized per process: re-read after a fork, but not on every test.
|
|
180
|
+
if @parallel_worker_id_env_pid != Process.pid
|
|
181
|
+
@parallel_worker_id_env_pid = Process.pid
|
|
182
|
+
@parallel_worker_id_from_env = parallel_worker_id_from_env
|
|
183
|
+
end
|
|
184
|
+
@parallel_worker_id_from_env
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Stamps per-process execution metadata on a result. Must be called
|
|
188
|
+
# in the process that ran the test so pid and per-process test index
|
|
189
|
+
# are captured worker-side.
|
|
190
|
+
#
|
|
191
|
+
# First writer wins: results that were already stamped are left
|
|
192
|
+
# untouched. Embedding environments that run tests in forked workers
|
|
193
|
+
# and transport results to another process (e.g. over DRb) MUST call
|
|
194
|
+
# this in the worker before sending, otherwise the stamp applied
|
|
195
|
+
# during reporting would carry the reporting process's pid and an
|
|
196
|
+
# arrival-order index interleaved across workers.
|
|
197
|
+
#
|
|
198
|
+
# The counter is mutex-guarded: results recorded from multiple threads
|
|
199
|
+
# (e.g. a DRb server dispatching each call on its own thread) get
|
|
200
|
+
# unique, gap-free indexes reflecting record order in this process.
|
|
201
|
+
# Returns the result when it was stamped, nil when it was skipped.
|
|
202
|
+
def stamp_parallel_worker_metadata(result)
|
|
203
|
+
return unless result.respond_to?(:parallel_worker_pid=)
|
|
204
|
+
return if result.parallel_worker_pid # already stamped worker-side
|
|
205
|
+
|
|
206
|
+
PARALLEL_WORKER_METADATA_MUTEX.synchronize do
|
|
207
|
+
pid = Process.pid
|
|
208
|
+
if @parallel_worker_metadata_pid != pid
|
|
209
|
+
# Restart the per-process counter in forked workers so that
|
|
210
|
+
# (parallel_worker_id, parallel_worker_pid, parallel_worker_test_index)
|
|
211
|
+
# always reflects execution order within a single process.
|
|
212
|
+
@parallel_worker_metadata_pid = pid
|
|
213
|
+
@parallel_worker_next_test_index = 0
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
result.parallel_worker_id = parallel_worker_id
|
|
217
|
+
result.parallel_worker_pid = pid
|
|
218
|
+
result.parallel_worker_test_index = @parallel_worker_next_test_index
|
|
219
|
+
@parallel_worker_next_test_index += 1
|
|
220
|
+
end
|
|
221
|
+
result
|
|
222
|
+
end
|
|
223
|
+
|
|
158
224
|
def queue
|
|
159
225
|
Minitest.queue
|
|
160
226
|
end
|
|
@@ -179,6 +245,8 @@ module Minitest
|
|
|
179
245
|
end
|
|
180
246
|
|
|
181
247
|
def handle_test_result(reporter, example, result)
|
|
248
|
+
stamp_parallel_worker_metadata(result)
|
|
249
|
+
|
|
182
250
|
if result.respond_to?(:queue_id=)
|
|
183
251
|
result.queue_id = example.id
|
|
184
252
|
result.queue_entry = example.queue_entry if result.respond_to?(:queue_entry=)
|
|
@@ -198,6 +266,7 @@ module Minitest
|
|
|
198
266
|
end
|
|
199
267
|
|
|
200
268
|
if failed && CI::Queue.requeueable?(result) && queue.requeue(example.queue_entry)
|
|
269
|
+
queue.report_requeue!
|
|
201
270
|
result.requeue!
|
|
202
271
|
if CI::Queue.debug?
|
|
203
272
|
$stderr.puts "[ci-queue][requeue] test_id=#{example.id} error_class=#{result.failures.first&.class} error=#{result.failures.first&.message&.lines&.first&.chomp}"
|
|
@@ -212,6 +281,17 @@ module Minitest
|
|
|
212
281
|
|
|
213
282
|
private
|
|
214
283
|
|
|
284
|
+
def parallel_worker_id_from_env
|
|
285
|
+
value = ENV['CI_QUEUE_PARALLEL_WORKER_ID']
|
|
286
|
+
return nil if value.nil? || value.empty?
|
|
287
|
+
|
|
288
|
+
begin
|
|
289
|
+
Integer(value)
|
|
290
|
+
rescue ArgumentError
|
|
291
|
+
value
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
|
|
215
295
|
def report_load_stats(queue)
|
|
216
296
|
return unless CI::Queue.debug?
|
|
217
297
|
return unless queue.respond_to?(:file_loader)
|
|
@@ -440,6 +520,7 @@ module Minitest
|
|
|
440
520
|
if result
|
|
441
521
|
result.start_timestamp = start_timestamp
|
|
442
522
|
result.finish_timestamp = current_timestamp
|
|
523
|
+
result.time ||= (result.finish_timestamp - result.start_timestamp).to_f
|
|
443
524
|
end
|
|
444
525
|
end
|
|
445
526
|
|
|
@@ -576,7 +657,7 @@ module Minitest
|
|
|
576
657
|
Queue.run(*args)
|
|
577
658
|
|
|
578
659
|
if queue.config.circuit_breakers.any?(&:open?)
|
|
579
|
-
STDERR.puts queue.config.circuit_breakers.map(&:message).join(' ').strip
|
|
660
|
+
STDERR.puts queue.config.circuit_breakers.select(&:open?).map(&:message).join(' ').strip
|
|
580
661
|
end
|
|
581
662
|
|
|
582
663
|
if queue.max_test_failed?
|
|
@@ -607,11 +688,13 @@ if defined? Minitest::Result
|
|
|
607
688
|
Minitest::Result.prepend(Minitest::Flakiness)
|
|
608
689
|
Minitest::Result.prepend(Minitest::WithTimestamps)
|
|
609
690
|
Minitest::Result.prepend(Minitest::ResultMetadata)
|
|
691
|
+
Minitest::Result.prepend(Minitest::ParallelWorkerMetadata)
|
|
610
692
|
else
|
|
611
693
|
Minitest::Test.prepend(Minitest::Requeueing)
|
|
612
694
|
Minitest::Test.prepend(Minitest::Flakiness)
|
|
613
695
|
Minitest::Test.prepend(Minitest::WithTimestamps)
|
|
614
696
|
Minitest::Test.prepend(Minitest::ResultMetadata)
|
|
697
|
+
Minitest::Test.prepend(Minitest::ParallelWorkerMetadata)
|
|
615
698
|
|
|
616
699
|
module MinitestBackwardCompatibility
|
|
617
700
|
def source_location
|
data/lib/rspec/queue.rb
CHANGED
|
@@ -158,6 +158,15 @@ module RSpec
|
|
|
158
158
|
queue_config.max_consecutive_failures = Integer(max)
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
help = <<~EOS
|
|
162
|
+
Defines after how many consecutive accepted requeues the worker will be considered unhealthy and stop reserving tests.
|
|
163
|
+
Defaults to disabled.
|
|
164
|
+
EOS
|
|
165
|
+
parser.separator ""
|
|
166
|
+
parser.on('--max-consecutive-requeues MAX', *help) do |max|
|
|
167
|
+
queue_config.max_consecutive_requeues = Integer(max)
|
|
168
|
+
end
|
|
169
|
+
|
|
161
170
|
help = <<~EOS
|
|
162
171
|
Defines how long the test report remain after the test run, in seconds.
|
|
163
172
|
Defaults to 28,800 (8 hours)
|
|
@@ -215,22 +224,21 @@ module RSpec
|
|
|
215
224
|
|
|
216
225
|
def finish(reporter, acknowledge: true)
|
|
217
226
|
if acknowledge && reporter.respond_to?(:requeue)
|
|
218
|
-
if @exception
|
|
219
|
-
reporter.report_failure!
|
|
220
|
-
else
|
|
221
|
-
reporter.report_success!
|
|
222
|
-
end
|
|
223
|
-
|
|
224
227
|
if @exception && CI::Queue.requeueable?(@exception) && reporter.requeue
|
|
228
|
+
reporter.report_requeue!
|
|
225
229
|
reporter.cancel_run!
|
|
226
230
|
dup.mark_as_requeued!(reporter)
|
|
227
231
|
return true
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
if @exception
|
|
235
|
+
reporter.report_failure!
|
|
228
236
|
else
|
|
229
|
-
|
|
237
|
+
reporter.report_success!
|
|
230
238
|
end
|
|
231
|
-
else
|
|
232
|
-
super(reporter)
|
|
233
239
|
end
|
|
240
|
+
|
|
241
|
+
super(reporter)
|
|
234
242
|
end
|
|
235
243
|
|
|
236
244
|
def reset!
|
|
@@ -417,6 +425,10 @@ module RSpec
|
|
|
417
425
|
@queue.report_failure!
|
|
418
426
|
end
|
|
419
427
|
|
|
428
|
+
def report_requeue!
|
|
429
|
+
@queue.report_requeue!
|
|
430
|
+
end
|
|
431
|
+
|
|
420
432
|
def requeue
|
|
421
433
|
@queue.requeue(@example.queue_entry)
|
|
422
434
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ci-queue
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.98.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jean Boussier
|
|
@@ -319,7 +319,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
319
319
|
- !ruby/object:Gem::Version
|
|
320
320
|
version: '0'
|
|
321
321
|
requirements: []
|
|
322
|
-
rubygems_version: 4.0.
|
|
322
|
+
rubygems_version: 4.0.16
|
|
323
323
|
specification_version: 4
|
|
324
324
|
summary: Distribute tests over many workers using a queue
|
|
325
325
|
test_files: []
|