ci-queue 0.96.0 → 0.97.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 +25 -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.rb +2 -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: 4d17fbfbe9128059d59548415b65bf99e86f6b9a3345ffd35c3e694bd1f5d1ec
|
|
4
|
+
data.tar.gz: e864440baac5ff4f930455e565509d78e7900243c251f2b5368e5bd2d8e1e114
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a7ecb6a7c387b76fab9d317bd619308cc6d4aa1d46684aa4c8a01546308613e1681fecabbebc4340bd9eb2dc8f68a8ca1e7fe0c19202c8b4224d4d260519bf1
|
|
7
|
+
data.tar.gz: d215b3fc1ef18fefa67493f2e447bc01a500224efbc61bc07c23bbb332e3dfe3855a73de16671ad8cdb2d59eeb1704a1765555d765b2d9a50532249b4f4d0280
|
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
|
|
|
@@ -158,6 +158,30 @@ rspec-queue --queue redis://example.com --timeout 600 --report
|
|
|
158
158
|
|
|
159
159
|
Because of how `ci-queue` executes the examples, `before(:all)` and `after(:all)` hooks are not supported. `rspec-queue` will explicitly reject them.
|
|
160
160
|
|
|
161
|
+
### Worker circuit breakers
|
|
162
|
+
|
|
163
|
+
Both runners support two independent, disabled-by-default circuit breakers:
|
|
164
|
+
|
|
165
|
+
- `--max-consecutive-failures MAX` stops a worker after `MAX` consecutive final test failures.
|
|
166
|
+
- `--max-consecutive-requeues MAX` stops a worker after `MAX` consecutive failures were accepted for requeueing.
|
|
167
|
+
|
|
168
|
+
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.
|
|
169
|
+
|
|
170
|
+
For example:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
minitest-queue --max-consecutive-requeues 10 --queue redis://example.com run test/**/*_test.rb
|
|
174
|
+
rspec-queue --max-consecutive-requeues 10 --queue redis://example.com
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
The breaker can also be configured programmatically:
|
|
178
|
+
|
|
179
|
+
```ruby
|
|
180
|
+
CI::Queue::Configuration.new(max_consecutive_requeues: 10)
|
|
181
|
+
# or
|
|
182
|
+
config.max_consecutive_requeues = 10
|
|
183
|
+
```
|
|
184
|
+
|
|
161
185
|
## Releasing a New Version
|
|
162
186
|
|
|
163
187
|
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
|
data/lib/minitest/queue.rb
CHANGED
|
@@ -198,6 +198,7 @@ module Minitest
|
|
|
198
198
|
end
|
|
199
199
|
|
|
200
200
|
if failed && CI::Queue.requeueable?(result) && queue.requeue(example.queue_entry)
|
|
201
|
+
queue.report_requeue!
|
|
201
202
|
result.requeue!
|
|
202
203
|
if CI::Queue.debug?
|
|
203
204
|
$stderr.puts "[ci-queue][requeue] test_id=#{example.id} error_class=#{result.failures.first&.class} error=#{result.failures.first&.message&.lines&.first&.chomp}"
|
|
@@ -576,7 +577,7 @@ module Minitest
|
|
|
576
577
|
Queue.run(*args)
|
|
577
578
|
|
|
578
579
|
if queue.config.circuit_breakers.any?(&:open?)
|
|
579
|
-
STDERR.puts queue.config.circuit_breakers.map(&:message).join(' ').strip
|
|
580
|
+
STDERR.puts queue.config.circuit_breakers.select(&:open?).map(&:message).join(' ').strip
|
|
580
581
|
end
|
|
581
582
|
|
|
582
583
|
if queue.max_test_failed?
|
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.97.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: []
|