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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8c3ced29dc916918cd28d47f312be55e014fd5836ab0c91d1e2eab17c9484951
4
- data.tar.gz: 3ac890363a4a861ca2c3420c24490dff1ffd89dfb890b8d0fd71062ccf812003
3
+ metadata.gz: 4d17fbfbe9128059d59548415b65bf99e86f6b9a3345ffd35c3e694bd1f5d1ec
4
+ data.tar.gz: e864440baac5ff4f930455e565509d78e7900243c251f2b5368e5bd2d8e1e114
5
5
  SHA512:
6
- metadata.gz: 27f198e8d9201f56112cc29bb3fcaa8518e7d5ddedc629d5eba13de06e0b936a8e809d47162d088f57d5ff614d3c4f92f003f786de62310ae421498e9913d8a9
7
- data.tar.gz: 2c5f925d28012585afa8212cbb14afb1966cb0a2e5dbeaa9927486b2e96fb2c96d595f06ef7aa5ab6b97e5c238e5bca01e3572273a8a5fa9e8be357f54c44bf5
6
+ metadata.gz: 0a7ecb6a7c387b76fab9d317bd619308cc6d4aa1d46684aa4c8a01546308613e1681fecabbebc4340bd9eb2dc8f68a8ca1e7fe0c19202c8b4224d4d260519bf1
7
+ data.tar.gz: d215b3fc1ef18fefa67493f2e447bc01a500224efbc61bc07c23bbb332e3dfe3855a73de16671ad8cdb2d59eeb1704a1765555d765b2d9a50532249b4f4d0280
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ci-queue (0.96.0)
4
+ ci-queue (0.97.0)
5
5
  logger
6
6
 
7
7
  GEM
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
@@ -27,6 +27,10 @@ module CI
27
27
  config.circuit_breakers.each(&:report_failure!)
28
28
  end
29
29
 
30
+ def report_requeue!
31
+ config.circuit_breakers.each(&:report_requeue!)
32
+ end
33
+
30
34
  def report_success!
31
35
  config.circuit_breakers.each(&:report_success!)
32
36
  end
@@ -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)
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.96.0'
5
+ VERSION = '0.97.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
@@ -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
@@ -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
- super(reporter)
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.96.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.11
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: []