ci-queue 0.40.0 → 0.42.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/dev.yml +1 -1
- data/lib/ci/queue/circuit_breaker.rb +1 -1
- data/lib/ci/queue/configuration.rb +4 -3
- data/lib/ci/queue/redis/base.rb +42 -7
- data/lib/ci/queue/redis/supervisor.rb +1 -1
- data/lib/ci/queue/redis/worker.rb +2 -2
- data/lib/ci/queue/redis.rb +0 -1
- data/lib/ci/queue/static.rb +1 -1
- data/lib/ci/queue/version.rb +1 -1
- data/lib/ci/queue.rb +9 -0
- data/lib/minitest/queue/runner.rb +9 -10
- data/lib/minitest/queue.rb +5 -8
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fb0b6d2c1537200e0a3540652972d25456cda0fe2115a65a884c8f5feeb17ff7
|
|
4
|
+
data.tar.gz: 7ac240806fdf6f16edfa314c59dccb22b379dbc2795d23d0c4ad19f4a46956d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: feaea129a7c672e57372e6475dc0fdc049c1e8b7815994b9ece3b4db0cbf6970ba19c222ed6bf9a652c7e68c7781e46edbd45e0eaa0da2b4e4d31b3856980aed
|
|
7
|
+
data.tar.gz: e2b9112e41b223c85b0acc20a7129d2ec517a816e73a42bea381ce696af8821dbaee1c5151d5002784630b1c0104b6c342d91b6273dd12de01c063d5bef5b1fe
|
data/dev.yml
CHANGED
|
@@ -5,7 +5,7 @@ module CI
|
|
|
5
5
|
attr_accessor :timeout, :worker_id, :max_requeues, :grind_count, :failure_file, :export_flaky_tests_file
|
|
6
6
|
attr_accessor :requeue_tolerance, :namespace, :failing_test, :statsd_endpoint
|
|
7
7
|
attr_accessor :max_test_duration, :max_test_duration_percentile, :track_test_duration
|
|
8
|
-
attr_accessor :max_test_failed, :redis_ttl, :warnings_file
|
|
8
|
+
attr_accessor :max_test_failed, :redis_ttl, :warnings_file, :debug_log
|
|
9
9
|
attr_reader :circuit_breakers
|
|
10
10
|
attr_writer :seed, :build_id
|
|
11
11
|
attr_writer :queue_init_timeout, :report_timeout, :inactive_workers_timeout
|
|
@@ -19,6 +19,7 @@ module CI
|
|
|
19
19
|
flaky_tests: load_flaky_tests(env['CI_QUEUE_FLAKY_TESTS']),
|
|
20
20
|
statsd_endpoint: env['CI_QUEUE_STATSD_ADDR'],
|
|
21
21
|
redis_ttl: env['CI_QUEUE_REDIS_TTL']&.to_i || 8 * 60 * 60,
|
|
22
|
+
debug_log: env['CI_QUEUE_DEBUG_LOG'],
|
|
22
23
|
)
|
|
23
24
|
end
|
|
24
25
|
|
|
@@ -36,8 +37,7 @@ module CI
|
|
|
36
37
|
grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
|
|
37
38
|
max_test_duration_percentile: 0.5, track_test_duration: false, max_test_failed: nil,
|
|
38
39
|
queue_init_timeout: nil, redis_ttl: 8 * 60 * 60, report_timeout: nil, inactive_workers_timeout: nil,
|
|
39
|
-
export_flaky_tests_file: nil, warnings_file: nil
|
|
40
|
-
)
|
|
40
|
+
export_flaky_tests_file: nil, warnings_file: nil, debug_log: nil)
|
|
41
41
|
@build_id = build_id
|
|
42
42
|
@circuit_breakers = [CircuitBreaker::Disabled]
|
|
43
43
|
@failure_file = failure_file
|
|
@@ -62,6 +62,7 @@ module CI
|
|
|
62
62
|
@inactive_workers_timeout = inactive_workers_timeout
|
|
63
63
|
@export_flaky_tests_file = export_flaky_tests_file
|
|
64
64
|
@warnings_file = warnings_file
|
|
65
|
+
@debug_log = debug_log
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
def queue_init_timeout
|
data/lib/ci/queue/redis/base.rb
CHANGED
|
@@ -11,15 +11,50 @@ module CI
|
|
|
11
11
|
::SocketError, # https://github.com/redis/redis-rb/pull/631
|
|
12
12
|
].freeze
|
|
13
13
|
|
|
14
|
+
module RedisInstrumentation
|
|
15
|
+
def call(command, redis_config)
|
|
16
|
+
result = super
|
|
17
|
+
logger = redis_config.custom[:debug_log]
|
|
18
|
+
logger.info("#{command}: #{result}")
|
|
19
|
+
result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def call_pipelined(commands, redis_config)
|
|
23
|
+
result = super
|
|
24
|
+
logger = redis_config.custom[:debug_log]
|
|
25
|
+
logger.info("#{commands}: #{result}")
|
|
26
|
+
result
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
14
30
|
def initialize(redis_url, config)
|
|
15
31
|
@redis_url = redis_url
|
|
16
|
-
@redis = ::Redis.new(
|
|
17
|
-
url: redis_url,
|
|
18
|
-
# Booting a CI worker is costly, so in case of a Redis blip,
|
|
19
|
-
# it makes sense to retry for a while before giving up.
|
|
20
|
-
reconnect_attempts: [0, 0, 0.1, 0.5, 1, 3, 5],
|
|
21
|
-
)
|
|
22
32
|
@config = config
|
|
33
|
+
if ::Redis::VERSION > "5.0.0"
|
|
34
|
+
@redis = ::Redis.new(
|
|
35
|
+
url: redis_url,
|
|
36
|
+
# Booting a CI worker is costly, so in case of a Redis blip,
|
|
37
|
+
# it makes sense to retry for a while before giving up.
|
|
38
|
+
reconnect_attempts: [0, 0, 0.1, 0.5, 1, 3, 5],
|
|
39
|
+
middlewares: custom_middlewares,
|
|
40
|
+
custom: custom_config,
|
|
41
|
+
)
|
|
42
|
+
else
|
|
43
|
+
@redis = ::Redis.new(url: redis_url)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def custom_config
|
|
48
|
+
return unless config.debug_log
|
|
49
|
+
|
|
50
|
+
require 'logger'
|
|
51
|
+
{ debug_log: Logger.new(config.debug_log) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def custom_middlewares
|
|
55
|
+
return unless config.debug_log
|
|
56
|
+
|
|
57
|
+
[RedisInstrumentation]
|
|
23
58
|
end
|
|
24
59
|
|
|
25
60
|
def exhausted?
|
|
@@ -28,7 +63,7 @@ module CI
|
|
|
28
63
|
|
|
29
64
|
def expired?
|
|
30
65
|
if (created_at = redis.get(key('created-at')))
|
|
31
|
-
(created_at.to_f + config.redis_ttl + TEN_MINUTES) <
|
|
66
|
+
(created_at.to_f + config.redis_ttl + TEN_MINUTES) < CI::Queue.time_now.to_f
|
|
32
67
|
else
|
|
33
68
|
# if there is no created at set anymore we assume queue is expired
|
|
34
69
|
true
|
|
@@ -46,7 +46,7 @@ module CI
|
|
|
46
46
|
|
|
47
47
|
def active_workers?
|
|
48
48
|
# if there are running jobs we assume there are still agents active
|
|
49
|
-
redis.zrangebyscore(key('running'),
|
|
49
|
+
redis.zrangebyscore(key('running'), CI::Queue.time_now.to_f - config.timeout, "+inf", limit: [0,1]).count > 0
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -175,7 +175,7 @@ module CI
|
|
|
175
175
|
key('worker', worker_id, 'queue'),
|
|
176
176
|
key('owners'),
|
|
177
177
|
],
|
|
178
|
-
argv: [
|
|
178
|
+
argv: [CI::Queue.time_now.to_f],
|
|
179
179
|
)
|
|
180
180
|
end
|
|
181
181
|
|
|
@@ -188,7 +188,7 @@ module CI
|
|
|
188
188
|
key('worker', worker_id, 'queue'),
|
|
189
189
|
key('owners'),
|
|
190
190
|
],
|
|
191
|
-
argv: [
|
|
191
|
+
argv: [CI::Queue.time_now.to_f, timeout],
|
|
192
192
|
)
|
|
193
193
|
|
|
194
194
|
if lost_test
|
data/lib/ci/queue/redis.rb
CHANGED
data/lib/ci/queue/static.rb
CHANGED
data/lib/ci/queue/version.rb
CHANGED
data/lib/ci/queue.rb
CHANGED
|
@@ -24,6 +24,15 @@ module CI
|
|
|
24
24
|
RESERVED_LOST_TEST = :RESERVED_LOST_TEST
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
GET_NOW = ::Time.method(:now)
|
|
28
|
+
private_constant :GET_NOW
|
|
29
|
+
def time_now
|
|
30
|
+
# Mocks like freeze_time should be cleaned when ci-queue runs, however,
|
|
31
|
+
# we experienced cases when tests were enqueued with wrong timestamps, so we
|
|
32
|
+
# safeguard Time.now here.
|
|
33
|
+
GET_NOW.call
|
|
34
|
+
end
|
|
35
|
+
|
|
27
36
|
def requeueable?(test_result)
|
|
28
37
|
requeueable.nil? || requeueable.call(test_result)
|
|
29
38
|
end
|
|
@@ -63,7 +63,7 @@ module Minitest
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
queue.rescue_connection_errors { queue.created_at =
|
|
66
|
+
queue.rescue_connection_errors { queue.created_at = CI::Queue.time_now.to_f }
|
|
67
67
|
|
|
68
68
|
set_load_path
|
|
69
69
|
Minitest.queue = queue
|
|
@@ -227,11 +227,11 @@ module Minitest
|
|
|
227
227
|
end
|
|
228
228
|
|
|
229
229
|
unless supervisor.exhausted?
|
|
230
|
+
reporter = BuildStatusReporter.new(build: supervisor.build)
|
|
231
|
+
reporter.report
|
|
230
232
|
msg = "#{supervisor.size} tests weren't run."
|
|
231
233
|
if supervisor.max_test_failed?
|
|
232
234
|
puts('Encountered too many failed tests. Test run was ended early.')
|
|
233
|
-
reporter = BuildStatusReporter.new(build: supervisor.build)
|
|
234
|
-
reporter.report
|
|
235
235
|
abort!(msg)
|
|
236
236
|
else
|
|
237
237
|
abort!(msg)
|
|
@@ -301,14 +301,9 @@ module Minitest
|
|
|
301
301
|
return unless queue_config.warnings_file
|
|
302
302
|
|
|
303
303
|
warnings = build.pop_warnings.map do |type, attributes|
|
|
304
|
-
|
|
305
|
-
when CI::Queue::Warnings::RESERVED_LOST_TEST
|
|
306
|
-
"[WARNING] #{attributes[:test]} was picked up by another worker because it didn't complete in the allocated #{attributes[:timeout]} seconds.\n" \
|
|
307
|
-
"You may want to either optimize this test or bump ci-queue timeout.\n" \
|
|
308
|
-
"It's also possible that the worker that was processing it was terminated without being able to report back.\n"
|
|
309
|
-
end
|
|
304
|
+
attributes.merge(type: type)
|
|
310
305
|
end.compact
|
|
311
|
-
File.write(queue_config.warnings_file, warnings.
|
|
306
|
+
File.write(queue_config.warnings_file, warnings.to_json)
|
|
312
307
|
end
|
|
313
308
|
|
|
314
309
|
def run_tests_in_fork(queue)
|
|
@@ -591,6 +586,10 @@ module Minitest
|
|
|
591
586
|
self.verbose = true
|
|
592
587
|
end
|
|
593
588
|
|
|
589
|
+
opts.on("--debug-log FILE", "Path to debug log file for e.g. Redis instrumentation") do |path|
|
|
590
|
+
queue_config.debug_log = path
|
|
591
|
+
end
|
|
592
|
+
|
|
594
593
|
opts.separator ""
|
|
595
594
|
opts.separator " retry: Replays a previous run in the same order."
|
|
596
595
|
|
data/lib/minitest/queue.rb
CHANGED
|
@@ -187,7 +187,7 @@ module Minitest
|
|
|
187
187
|
private
|
|
188
188
|
|
|
189
189
|
def current_timestamp
|
|
190
|
-
|
|
190
|
+
CI::Queue.time_now.to_i
|
|
191
191
|
end
|
|
192
192
|
end
|
|
193
193
|
|
|
@@ -244,20 +244,17 @@ module Minitest
|
|
|
244
244
|
queue.report_success!
|
|
245
245
|
end
|
|
246
246
|
|
|
247
|
-
requeued = false
|
|
248
247
|
if failed && CI::Queue.requeueable?(result) && queue.requeue(example)
|
|
249
|
-
requeued = true
|
|
250
248
|
result.requeue!
|
|
251
249
|
reporter.record(result)
|
|
252
|
-
elsif queue.acknowledge(example)
|
|
250
|
+
elsif queue.acknowledge(example)
|
|
251
|
+
reporter.record(result)
|
|
252
|
+
queue.increment_test_failed if failed
|
|
253
|
+
elsif !failed
|
|
253
254
|
# If the test was already acknowledged by another worker (we timed out)
|
|
254
255
|
# Then we only record it if it is successful.
|
|
255
256
|
reporter.record(result)
|
|
256
257
|
end
|
|
257
|
-
|
|
258
|
-
if !requeued && failed
|
|
259
|
-
queue.increment_test_failed
|
|
260
|
-
end
|
|
261
258
|
end
|
|
262
259
|
end
|
|
263
260
|
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.
|
|
4
|
+
version: 0.42.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:
|
|
11
|
+
date: 2024-01-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -239,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
239
239
|
- !ruby/object:Gem::Version
|
|
240
240
|
version: '0'
|
|
241
241
|
requirements: []
|
|
242
|
-
rubygems_version: 3.4
|
|
242
|
+
rubygems_version: 3.5.4
|
|
243
243
|
signing_key:
|
|
244
244
|
specification_version: 4
|
|
245
245
|
summary: Distribute tests over many workers using a queue
|