ci-queue 0.12.1 → 0.13.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: 9f86ba12b294a5698c6b1fa568d5482f549758e54ea85db004507a498a7477f1
4
- data.tar.gz: bc54f7c6890c5c1d172a634cafa961a8a5bb76980eed482a7fb0ef8fe1dcaad8
3
+ metadata.gz: d494a80d73d0f5f6d8b478f30b40b8dc2ed90e24031ca6ae96dade3a1995a75e
4
+ data.tar.gz: 4504d20539f933366c50f96b094cbc0ae3623556d62516b763dd98f5a1c305df
5
5
  SHA512:
6
- metadata.gz: bbc243b619402d0b4addf5cb85a9ac4bfa91668a9abd5b6d6c3ab48bc47a317271a2efa8bea88f4e3a9e733f3832ba731ba1afb0c21e8e330fda86f87218586b
7
- data.tar.gz: d7b7f715153b663757f4ee60c3f2bd7236e3b7b9308e1577e8e95b26a4af8b7892965cfabc8ca61847c09c39eb73b5ce3463ccede6e209046f7d5e8e21bf474d
6
+ metadata.gz: 632de17b6e079142195e34d4b9ac0e3754091f786a430f3e0e82ee282fb4d7b7823c89b8c3ab30c397f228c80b37575420affc34da8f0b1ef5fe23f7e325494c
7
+ data.tar.gz: 00fa21726fcd0c584af82ffc32fa6a32fc78dbe0672ec2916350890e0c9fa6a00205af9a195e7382c3518183c6d63b9745106b6f1255b5672ab121f34f64f712
@@ -3,7 +3,9 @@ require 'cgi'
3
3
 
4
4
  require 'ci/queue/version'
5
5
  require 'ci/queue/output_helpers'
6
+ require 'ci/queue/circuit_breaker'
6
7
  require 'ci/queue/configuration'
8
+ require 'ci/queue/common'
7
9
  require 'ci/queue/build_record'
8
10
  require 'ci/queue/static'
9
11
  require 'ci/queue/file'
@@ -0,0 +1,36 @@
1
+ module CI
2
+ module Queue
3
+ class CircuitBreaker
4
+ module Disabled
5
+ extend self
6
+
7
+ def report_failure!
8
+ end
9
+
10
+ def report_success!
11
+ end
12
+
13
+ def open?
14
+ false
15
+ end
16
+ end
17
+
18
+ def initialize(max_consecutive_failures:)
19
+ @max = max_consecutive_failures
20
+ @consecutive_failures = 0
21
+ end
22
+
23
+ def report_failure!
24
+ @consecutive_failures += 1
25
+ end
26
+
27
+ def report_success!
28
+ @consecutive_failures = 0
29
+ end
30
+
31
+ def open?
32
+ @consecutive_failures >= @max
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module CI
2
+ module Queue
3
+ module Common
4
+ attr_reader :config
5
+
6
+ def flaky?(test)
7
+ @config.flaky?(test)
8
+ end
9
+
10
+ def report_failure!
11
+ config.circuit_breaker.report_failure!
12
+ end
13
+
14
+ def report_success!
15
+ config.circuit_breaker.report_success!
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,9 +1,9 @@
1
-
2
1
  module CI
3
2
  module Queue
4
3
  class Configuration
5
4
  attr_accessor :timeout, :build_id, :worker_id, :max_requeues
6
5
  attr_accessor :requeue_tolerance, :namespace, :seed, :failing_test, :statsd_endpoint
6
+ attr_reader :circuit_breaker
7
7
 
8
8
  class << self
9
9
  def from_env(env)
@@ -26,7 +26,7 @@ module CI
26
26
 
27
27
  def initialize(
28
28
  timeout: 30, build_id: nil, worker_id: nil, max_requeues: 0, requeue_tolerance: 0,
29
- namespace: nil, seed: nil, flaky_tests: [], statsd_endpoint: nil
29
+ namespace: nil, seed: nil, flaky_tests: [], statsd_endpoint: nil, max_consecutive_failures: nil
30
30
  )
31
31
  @namespace = namespace
32
32
  @timeout = timeout
@@ -37,6 +37,15 @@ module CI
37
37
  @seed = seed
38
38
  @flaky_tests = flaky_tests
39
39
  @statsd_endpoint = statsd_endpoint
40
+ self.max_consecutive_failures = max_consecutive_failures
41
+ end
42
+
43
+ def max_consecutive_failures=(max)
44
+ @circuit_breaker = if max
45
+ CircuitBreaker.new(max_consecutive_failures: max)
46
+ else
47
+ CircuitBreaker::Disabled
48
+ end
40
49
  end
41
50
 
42
51
  def flaky?(test)
@@ -2,16 +2,14 @@ module CI
2
2
  module Queue
3
3
  module Redis
4
4
  class Base
5
+ include Common
6
+
5
7
  def initialize(redis_url, config)
6
8
  @redis_url = redis_url
7
9
  @redis = ::Redis.new(url: redis_url)
8
10
  @config = config
9
11
  end
10
12
 
11
- def flaky?(test)
12
- @config.flaky?(test)
13
- end
14
-
15
13
  def exhausted?
16
14
  queue_initialized? && size == 0
17
15
  end
@@ -59,7 +57,7 @@ module CI
59
57
 
60
58
  private
61
59
 
62
- attr_reader :redis, :config, :redis_url
60
+ attr_reader :redis, :redis_url
63
61
 
64
62
  def key(*args)
65
63
  ['build', build_id, *args].join(':')
@@ -44,7 +44,7 @@ module CI
44
44
 
45
45
  def poll
46
46
  wait_for_master
47
- until shutdown_required? || exhausted?
47
+ until shutdown_required? || config.circuit_breaker.open? || exhausted?
48
48
  if test = reserve
49
49
  yield index.fetch(test)
50
50
  else
@@ -1,6 +1,7 @@
1
1
  module CI
2
2
  module Queue
3
3
  class Static
4
+ include Common
4
5
  class << self
5
6
  def from_uri(uri, config)
6
7
  tests = uri.opaque.split(':').map { |t| CGI.unescape(t) }
@@ -17,10 +18,6 @@ module CI
17
18
  @total = tests.size
18
19
  end
19
20
 
20
- def flaky?(test)
21
- @config.flaky?(test)
22
- end
23
-
24
21
  def build
25
22
  @build ||= BuildRecord.new(self)
26
23
  end
@@ -51,7 +48,7 @@ module CI
51
48
  end
52
49
 
53
50
  def poll
54
- while test = @queue.shift
51
+ while !config.circuit_breaker.open? && test = @queue.shift
55
52
  yield index.fetch(test)
56
53
  @progress += 1
57
54
  end
@@ -75,7 +72,7 @@ module CI
75
72
 
76
73
  private
77
74
 
78
- attr_reader :index, :config
75
+ attr_reader :index
79
76
 
80
77
  def should_requeue?(key)
81
78
  requeues[key] < config.max_requeues && requeues.values.inject(0, :+) < config.global_max_requeues(total)
@@ -1,6 +1,6 @@
1
1
  module CI
2
2
  module Queue
3
- VERSION = '0.12.1'
3
+ VERSION = '0.13.0'
4
4
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
5
5
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
6
6
  end
@@ -143,6 +143,10 @@ module Minitest
143
143
  def __run(*args)
144
144
  if queue
145
145
  run_from_queue(*args)
146
+
147
+ if queue.config.circuit_breaker.open?
148
+ STDERR.puts "This worker is exiting early because it encountered too many consecutive test failures, probably because of some corrupted state."
149
+ end
146
150
  else
147
151
  super
148
152
  end
@@ -158,6 +162,12 @@ module Minitest
158
162
  failed = false
159
163
  end
160
164
 
165
+ if failed
166
+ queue.report_failure!
167
+ else
168
+ queue.report_success!
169
+ end
170
+
161
171
  if failed && queue.requeue(example)
162
172
  result.requeue!
163
173
  reporter.record(result)
@@ -271,6 +271,15 @@ module Minitest
271
271
  queue_config.requeue_tolerance = Float(ratio)
272
272
  end
273
273
 
274
+ help = split_heredoc(<<-EOS)
275
+ Defines after how many consecutive failures the worker will be considered unhealthy and terminate itself.
276
+ Defaults to disabled.
277
+ EOS
278
+ opts.separator ""
279
+ opts.on('--max-consecutive-failures MAX', *help) do |max|
280
+ queue_config.max_consecutive_failures = Integer(max)
281
+ end
282
+
274
283
  opts.separator ""
275
284
  opts.separator " retry: Replays a previous run in the same order."
276
285
 
@@ -135,6 +135,15 @@ module RSpec
135
135
  queue_config.requeue_tolerance = Float(ratio)
136
136
  end
137
137
 
138
+ help = split_heredoc(<<-EOS)
139
+ Defines after how many consecutive failures the worker will be considered unhealthy and terminate itself.
140
+ Defaults to disabled.
141
+ EOS
142
+ parser.separator ""
143
+ parser.on('--max-consecutive-failures MAX', *help) do |max|
144
+ queue_config.max_consecutive_failures = Integer(max)
145
+ end
146
+
138
147
  parser
139
148
  end
140
149
 
@@ -187,6 +196,12 @@ module RSpec
187
196
 
188
197
  def finish(reporter, acknowledge: true)
189
198
  if acknowledge && reporter.respond_to?(:requeue)
199
+ if @exception
200
+ reporter.report_failure!
201
+ else
202
+ reporter.report_success!
203
+ end
204
+
190
205
  if @exception && reporter.requeue
191
206
  reporter.cancel_run!
192
207
  dup.mark_as_requeued!(reporter)
@@ -301,6 +316,14 @@ module RSpec
301
316
  super(reporter)
302
317
  end
303
318
 
319
+ def report_success!
320
+ @queue.report_success!
321
+ end
322
+
323
+ def report_failure!
324
+ @queue.report_failure!
325
+ end
326
+
304
327
  def requeue
305
328
  @queue.requeue(@example)
306
329
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ci-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-06 00:00:00.000000000 Z
11
+ date: 2018-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ansi
@@ -174,6 +174,8 @@ files:
174
174
  - lib/ci/queue.rb
175
175
  - lib/ci/queue/bisect.rb
176
176
  - lib/ci/queue/build_record.rb
177
+ - lib/ci/queue/circuit_breaker.rb
178
+ - lib/ci/queue/common.rb
177
179
  - lib/ci/queue/configuration.rb
178
180
  - lib/ci/queue/file.rb
179
181
  - lib/ci/queue/output_helpers.rb