ci-queue 0.90.0 → 0.92.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: c5233596f5e87ddd8954a44a2b7c2be3d258ade0c567ff808b32d99194d89a7b
4
- data.tar.gz: 1026734a1076455a5ac95821ef8a1dbba83cb8ed445720fab8ca93cdd53eb693
3
+ metadata.gz: add1590f9cc361b896a70a61c456eb18f3bdcf9b6fd58aaf1432aa276c2cef48
4
+ data.tar.gz: 5a6ce1545cefa80a46b499286fb7de228a2c7c35c507af1e10728389f1951aac
5
5
  SHA512:
6
- metadata.gz: 68b5ce15acc1b90b3c75fb861ad8ea2ff6599c44d096a96ed5d018fa8d4eb4c6c20a9949950e31284436241d9d1df5c2917430eadef673872c9e4a693893ed20
7
- data.tar.gz: a1ba50c8998de99d54620efd899bc1a471b0bf037a3cb9a9e056b36d45f551f9430a9bac1b4f46713c5e17426fc7e409be4b307f77071321a9f0789c0eca5ee8
6
+ metadata.gz: 90a0e14eb954c3fba2f54eb680a523072a518d92aa2fa56584a93568f812f60f2ba7d6a656eba0370a5be8ff5da42c03727307b854edced06ad7e15e31f2eab3
7
+ data.tar.gz: '0716598054eb0b32c0453debb67a47656b266d35c14bf85a42e66503216c1617868d9dd081fc738852f74a31f66d622825523b451c0e6ab3fc3fcacd287aa162'
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ci-queue (0.90.0)
4
+ ci-queue (0.92.0)
5
5
  logger
6
6
 
7
7
  GEM
@@ -6,6 +6,7 @@ module CI
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
8
  attr_accessor :max_test_failed, :redis_ttl, :warnings_file, :debug_log, :max_missed_heartbeat_seconds
9
+ attr_writer :heartbeat_max_test_duration
9
10
  attr_accessor :lazy_load, :lazy_load_stream_batch_size
10
11
  attr_writer :lazy_load_streaming_timeout
11
12
  attr_accessor :lazy_load_test_helpers
@@ -57,7 +58,7 @@ module CI
57
58
  grind_count: nil, max_duration: nil, failure_file: nil, max_test_duration: nil,
58
59
  max_test_duration_percentile: 0.5, track_test_duration: false, max_test_failed: nil,
59
60
  queue_init_timeout: nil, redis_ttl: 8 * 60 * 60, report_timeout: nil, inactive_workers_timeout: nil,
60
- export_flaky_tests_file: nil, warnings_file: nil, debug_log: nil, max_missed_heartbeat_seconds: nil,
61
+ export_flaky_tests_file: nil, warnings_file: nil, debug_log: nil, max_missed_heartbeat_seconds: nil, heartbeat_max_test_duration: nil,
61
62
  lazy_load: false, lazy_load_stream_batch_size: nil, lazy_load_streaming_timeout: nil, lazy_load_test_helpers: nil,
62
63
  skip_stale_tests: false)
63
64
  @build_id = build_id
@@ -86,6 +87,7 @@ module CI
86
87
  @warnings_file = warnings_file
87
88
  @debug_log = debug_log
88
89
  @max_missed_heartbeat_seconds = max_missed_heartbeat_seconds
90
+ @heartbeat_max_test_duration = heartbeat_max_test_duration
89
91
  @lazy_load = lazy_load
90
92
  @lazy_load_stream_batch_size = lazy_load_stream_batch_size || 5_000
91
93
  @lazy_load_streaming_timeout = lazy_load_streaming_timeout
@@ -153,6 +155,10 @@ module CI
153
155
  @inactive_workers_timeout || timeout
154
156
  end
155
157
 
158
+ def heartbeat_max_test_duration
159
+ @heartbeat_max_test_duration || (timeout * 10 if max_missed_heartbeat_seconds)
160
+ end
161
+
156
162
  def max_consecutive_failures=(max)
157
163
  if max
158
164
  @circuit_breakers << CircuitBreaker::MaxConsecutiveFailures.new(max_consecutive_failures: max)
@@ -63,7 +63,7 @@ module CI
63
63
  def with_heartbeat(id, lease: nil)
64
64
  if heartbeat_enabled?
65
65
  ensure_heartbeat_thread_alive!
66
- heartbeat_state.set(:tick, id, lease)
66
+ heartbeat_state.set(:tick, id, lease, Process.clock_gettime(Process::CLOCK_MONOTONIC))
67
67
  end
68
68
 
69
69
  yield
@@ -266,6 +266,11 @@ module CI
266
266
  class HeartbeatProcess
267
267
  MAX_RESTART_ATTEMPTS = 3
268
268
 
269
+ # Cached command marker. Passing this frozen String instead of the
270
+ # :tick! Symbol avoids allocating a 'tick!' String (from Symbol#to_s)
271
+ # on every heartbeat, which fires once per running test per worker.
272
+ TICK_COMMAND = 'tick!'.freeze
273
+
269
274
  def initialize(redis_url, zset_key, owners_key, leases_key)
270
275
  @redis_url = redis_url
271
276
  @zset_key = zset_key
@@ -314,7 +319,7 @@ module CI
314
319
  end
315
320
 
316
321
  def tick!(id, lease)
317
- send_message(:tick!, id: id, lease: lease.to_s)
322
+ send_message(TICK_COMMAND, id: id, lease: lease.to_s)
318
323
  @restart_attempts = 0
319
324
  rescue IOError, Errno::EPIPE => error
320
325
  @restart_attempts = (@restart_attempts || 0) + 1
@@ -386,16 +391,32 @@ module CI
386
391
  Thread.current.name = "CI::Queue#heartbeat"
387
392
  Thread.current.abort_on_exception = true
388
393
 
394
+ capped = false
395
+
389
396
  loop do
390
397
  command = heartbeat_state.wait(1) # waits for max 1 second but wakes up immediately if we receive a command
391
398
 
392
399
  case command&.first
393
400
  when :tick
394
- # command = [:tick, entry_id, lease_id]
401
+ next if capped
402
+
403
+ max_duration = config.heartbeat_max_test_duration
404
+ if max_duration
405
+ # command = [:tick, entry_id, lease_id, started_at]
406
+ # Use the absolute start time from when with_heartbeat was called so that
407
+ # the elapsed calculation is not skewed by heartbeat thread startup delay.
408
+ elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - command[3]
409
+ if elapsed >= max_duration
410
+ capped = true
411
+ next
412
+ end
413
+ end
414
+
415
+ # command = [:tick, entry_id, lease_id, started_at]
395
416
  heartbeat_process.tick!(command[1], command[2])
396
417
  when :reset
397
418
  # Test finished, stop ticking until next test starts
398
- nil
419
+ capped = false
399
420
  when :stop
400
421
  break
401
422
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.90.0'
5
+ VERSION = '0.92.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
@@ -736,6 +736,16 @@ module Minitest
736
736
  queue_config.max_missed_heartbeat_seconds = time || 30
737
737
  end
738
738
 
739
+ help = <<~EOS
740
+ Maximum duration in seconds that the heartbeat will tick for a single test.
741
+ If a test runs longer than this, the heartbeat stops and the test entry becomes
742
+ eligible for reclamation by another worker.
743
+ Defaults to timeout * 10 when heartbeat is enabled.
744
+ EOS
745
+ opts.on("--heartbeat-max-test-duration SECONDS", Float, help) do |seconds|
746
+ queue_config.heartbeat_max_test_duration = seconds
747
+ end
748
+
739
749
 
740
750
  opts.on("-v", "--verbose", "Verbose. Show progress processing files.") do
741
751
  self.verbose = true
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.90.0
4
+ version: 0.92.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
@@ -305,7 +305,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
305
305
  - !ruby/object:Gem::Version
306
306
  version: '0'
307
307
  requirements: []
308
- rubygems_version: 4.0.9
308
+ rubygems_version: 4.0.10
309
309
  specification_version: 4
310
310
  summary: Distribute tests over many workers using a queue
311
311
  test_files: []