ci-queue 0.100.0 → 0.102.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: 64510328261d26c0b3299aa0e1bb4bbbb2fdd4f784293a304cec028527d25e8b
4
- data.tar.gz: 8cf5e99fcf74935b71a2ee6814cfc7565b03b1b314af8380f999f4228400417c
3
+ metadata.gz: 24f5d0ca5b0d0391a953c6f0014635eec1b6ea541e7ac46a944ac413952777e0
4
+ data.tar.gz: aeec01bc647d5fb960449d57362cc6961479f5c6da78177c915c35bd9706f861
5
5
  SHA512:
6
- metadata.gz: c044a9cafe05602f22debf2ea91b5cc63c42dabc67f8689b88430c7c34ece68da7bf7ad03b62036648073c8225e3588382bce588f486359b339a65aa62e71951
7
- data.tar.gz: 5d9f475df1260d6cc6cd04d1f1ceec0ca28e7b12e9d5d0b0931ac7b18a2e864a5a2386f102f878a8392722dbb535e260b8661e5ccc5722097ee8d8e866d977dc
6
+ metadata.gz: 896cb4ac3e81d1235581e11ce6a0693565c6089afc441546a94d7211eab24b538279dfd6eb5abe06d7e3187e1b54bfb0f5d4127baa06d49a12baf181b345a444
7
+ data.tar.gz: 0be6036f02910f31672c28e2d6c6eb4cdbd41f066ffb499eed8e10990b2a7a8e6d596ecf9c3da5c57c574fc0a76ac73b430d447781c2929f615a2aa669ecbe74
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ci-queue (0.100.0)
4
+ ci-queue (0.102.0)
5
5
  logger
6
6
 
7
7
  GEM
@@ -12,10 +12,30 @@ local leases_key = KEYS[9]
12
12
  local max_requeues = tonumber(ARGV[1])
13
13
  local global_max_requeues = tonumber(ARGV[2])
14
14
  local entry = ARGV[3]
15
- local offset = ARGV[4]
15
+ local offset = tonumber(ARGV[4]) or 0
16
16
  local ttl = tonumber(ARGV[5])
17
17
  local lease_id = ARGV[6]
18
18
 
19
+ -- Inserts `entry` behind the `offset` + 1 entries nearest the tail, the end RPOP reserves
20
+ -- from: where `LINSERT BEFORE <entry at index -(offset + 1)>` would put it. LINSERT finds its
21
+ -- pivot by scanning from the head, which is O(queue length) and blocks Redis on large queues;
22
+ -- this only touches the tail, so it is O(offset). Queues of at most `offset` + 1 entries, and
23
+ -- offsets of zero or less, push to the head instead.
24
+ -- Keep in sync with reserve.lua: the Python client does not resolve `-- @include`.
25
+ local function insert_with_offset(queue_key, entry, offset)
26
+ if offset <= 0 or redis.call('llen', queue_key) <= offset + 1 then
27
+ redis.call('lpush', queue_key, entry)
28
+ return
29
+ end
30
+
31
+ local ahead = redis.call('lrange', queue_key, -1 - offset, -1)
32
+ redis.call('ltrim', queue_key, 0, -2 - offset)
33
+ redis.call('rpush', queue_key, entry)
34
+ for _, ahead_entry in ipairs(ahead) do
35
+ redis.call('rpush', queue_key, ahead_entry)
36
+ end
37
+ end
38
+
19
39
  -- Only the current lease holder can requeue a test.
20
40
  -- If the lease was transferred (e.g. via reserve_lost), reject the stale
21
41
  -- worker's requeue so the running entry stays intact for the new holder.
@@ -42,12 +62,7 @@ redis.call('hincrby', requeues_count_key, entry, 1)
42
62
 
43
63
  redis.call('hdel', error_reports_key, entry)
44
64
 
45
- local pivot = redis.call('lrange', queue_key, -1 - offset, 0 - offset)[1]
46
- if pivot then
47
- redis.call('linsert', queue_key, 'BEFORE', pivot, entry)
48
- else
49
- redis.call('lpush', queue_key, entry)
50
- end
65
+ insert_with_offset(queue_key, entry, offset)
51
66
 
52
67
  redis.call('hset', requeued_by_key, entry, worker_queue_key)
53
68
  if ttl and ttl > 0 then
@@ -13,12 +13,23 @@ local current_time = ARGV[1]
13
13
  local defer_offset = tonumber(ARGV[2]) or 0
14
14
  local max_skip_attempts = 4
15
15
 
16
- local function insert_with_offset(test)
17
- local pivot = redis.call('lrange', queue_key, -1 - defer_offset, 0 - defer_offset)[1]
18
- if pivot then
19
- redis.call('linsert', queue_key, 'BEFORE', pivot, test)
20
- else
21
- redis.call('lpush', queue_key, test)
16
+ -- Inserts `entry` behind the `offset` + 1 entries nearest the tail, the end RPOP reserves
17
+ -- from: where `LINSERT BEFORE <entry at index -(offset + 1)>` would put it. LINSERT finds its
18
+ -- pivot by scanning from the head, which is O(queue length) and blocks Redis on large queues;
19
+ -- this only touches the tail, so it is O(offset). Queues of at most `offset` + 1 entries, and
20
+ -- offsets of zero or less, push to the head instead.
21
+ -- Keep in sync with requeue.lua: the Python client does not resolve `-- @include`.
22
+ local function insert_with_offset(queue_key, entry, offset)
23
+ if offset <= 0 or redis.call('llen', queue_key) <= offset + 1 then
24
+ redis.call('lpush', queue_key, entry)
25
+ return
26
+ end
27
+
28
+ local ahead = redis.call('lrange', queue_key, -1 - offset, -1)
29
+ redis.call('ltrim', queue_key, 0, -2 - offset)
30
+ redis.call('rpush', queue_key, entry)
31
+ for _, ahead_entry in ipairs(ahead) do
32
+ redis.call('rpush', queue_key, ahead_entry)
22
33
  end
23
34
  end
24
35
 
@@ -45,7 +56,7 @@ for attempt = 1, max_skip_attempts do
45
56
  return claim_test(test)
46
57
  end
47
58
 
48
- insert_with_offset(test)
59
+ insert_with_offset(queue_key, test, defer_offset)
49
60
 
50
61
  -- If this worker only finds its own requeued tests, defer once by returning nil,
51
62
  -- then allow pickup on a subsequent reserve attempt.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CI
4
4
  module Queue
5
- VERSION = '0.100.0'
5
+ VERSION = '0.102.0'
6
6
  DEV_SCRIPTS_ROOT = ::File.expand_path('../../../../../redis', __FILE__)
7
7
  RELEASE_SCRIPTS_ROOT = ::File.expand_path('../redis', __FILE__)
8
8
  end
@@ -304,7 +304,11 @@ module Minitest
304
304
  step("Waiting for workers to complete")
305
305
 
306
306
  unless supervisor.wait_for_workers { display_warnings(supervisor.build) }
307
- unless supervisor.queue_initialized?
307
+ # A lazy-load leader only marks the queue as initialized once it has
308
+ # streamed every test, but workers start on the first batch, so the wait
309
+ # can end (e.g. on --max-test-failed) while it is still streaming.
310
+ # Check streaming? first: the status only moves from streaming to ready.
311
+ unless supervisor.streaming? || supervisor.queue_initialized?
308
312
  abort! "No leader was elected. This typically means no worker was able to start. Were there any errors during application boot?", 40
309
313
  end
310
314
 
@@ -314,7 +318,7 @@ module Minitest
314
318
  reporter.write_failure_file(queue_config.failure_file) if queue_config.failure_file
315
319
  reporter.write_flaky_tests_file(queue_config.export_flaky_tests_file) if queue_config.export_flaky_tests_file
316
320
 
317
- abort!("#{supervisor.size} tests weren't run.", exit_code)
321
+ abort!(unrun_tests_message(supervisor), exit_code)
318
322
  end
319
323
  end
320
324
 
@@ -447,6 +451,16 @@ module Minitest
447
451
  Minitest::Queue::WorkerProfileReporter.new(supervisor).print_summary
448
452
  end
449
453
 
454
+ def unrun_tests_message(supervisor)
455
+ # Read the status before the size: tests a streaming leader hasn't pushed
456
+ # yet aren't in the queue, so the size is only a lower bound.
457
+ if supervisor.streaming?
458
+ "At least #{supervisor.size} tests weren't run (the leader hadn't finished streaming tests to the queue)."
459
+ else
460
+ "#{supervisor.size} tests weren't run."
461
+ end
462
+ end
463
+
450
464
  def parser
451
465
  @parser ||= OptionParser.new do |opts|
452
466
  opts.banner = "Usage: minitest-queue [options] COMMAND [ARGS]"
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.100.0
4
+ version: 0.102.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier