ci-queue 0.40.0 → 0.42.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: be4adb99c549118b56b3b989e226acd24276f2105cd407ebe7c60685b439712f
4
- data.tar.gz: 53ad2297734965e9eb942710e6c6e0dcff81b2597d864f1c0336cbf88c5b792d
3
+ metadata.gz: fb0b6d2c1537200e0a3540652972d25456cda0fe2115a65a884c8f5feeb17ff7
4
+ data.tar.gz: 7ac240806fdf6f16edfa314c59dccb22b379dbc2795d23d0c4ad19f4a46956d1
5
5
  SHA512:
6
- metadata.gz: c5748d3f7cb1b9a9dd9cd386394c6e812f900fe7883686e920b8d2375fbb4fbfaf6c1a1a78703866f1bc3a64bf704cb21188c9fe3b1ddf762490aa1a36344770
7
- data.tar.gz: d8d146b0427253a80d1ad3739d976bef95bf43fbee151b59fb3810d75450cfb3f3dbddd2a0825c9aea966b44d2c3226874fb182940a473e27873f526f2d7564b
6
+ metadata.gz: feaea129a7c672e57372e6475dc0fdc049c1e8b7815994b9ece3b4db0cbf6970ba19c222ed6bf9a652c7e68c7781e46edbd45e0eaa0da2b4e4d31b3856980aed
7
+ data.tar.gz: e2b9112e41b223c85b0acc20a7129d2ec517a816e73a42bea381ce696af8821dbaee1c5151d5002784630b1c0104b6c342d91b6273dd12de01c063d5bef5b1fe
data/dev.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  name: ci-queue
4
4
 
5
5
  up:
6
- - ruby: 3.2.0
6
+ - ruby: 3.3.0
7
7
  - bundler
8
8
  - redis
9
9
 
@@ -46,7 +46,7 @@ module CI
46
46
  private
47
47
 
48
48
  def current_timestamp
49
- Time.now.to_i
49
+ CI::Queue.time_now.to_i
50
50
  end
51
51
  end
52
52
 
@@ -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
@@ -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) < Time.now.to_f
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'), Time.now.to_f - config.timeout, "+inf", limit: [0,1]).count > 0
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: [Time.now.to_f],
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: [Time.now.to_f, timeout],
191
+ argv: [CI::Queue.time_now.to_f, timeout],
192
192
  )
193
193
 
194
194
  if lost_test
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem 'redis', '>= 5'
4
3
  require 'redis'
5
4
  require 'ci/queue/redis/build_record'
6
5
  require 'ci/queue/redis/base'
@@ -53,7 +53,7 @@ module CI
53
53
  end
54
54
 
55
55
  def expired?
56
- (@created_at.to_f TEN_MINUTES) < Time.now.to_f
56
+ (@created_at.to_f TEN_MINUTES) < CI::Queue.time_now.to_f
57
57
  end
58
58
 
59
59
  def populated?
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.40.0'
5
+ VERSION = '0.42.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
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 = Time.now.to_f }
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
- case type
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.join("\n"))
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
 
@@ -187,7 +187,7 @@ module Minitest
187
187
  private
188
188
 
189
189
  def current_timestamp
190
- Time.now.to_i
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) || !failed
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.40.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: 2023-12-21 00:00:00.000000000 Z
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.22
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