ci-queue 0.12.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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