ci-queue 0.5.1 → 0.5.2
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/lib/ci/queue/redis/worker.rb +80 -52
- data/lib/ci/queue/static.rb +8 -11
- data/lib/ci/queue/version.rb +1 -1
- data/lib/minitest/queue.rb +7 -2
- data/lib/minitest/reporters/redis_reporter.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 442794179d88fc5fc9a2c3a781b5056ff27ee013
|
4
|
+
data.tar.gz: 03fa2c61961e02864f122854c9c21e09c0e2b387
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ca06529e6a43ec5100ce6d4da2c6ab1bd1f439f36706349e41da7b4653cd3879dc58243626687505a9fb63dd8fb714fc83c886c032c2db6c923fb24aa35c0a16
|
7
|
+
data.tar.gz: 7971b3b1d661227e89f1b2b807c8a060ae951748afa1ddd0eb5357285f2da39c16dbb1dd294661da605362d0dcff804f9267505cf9503e57ea35a8882eca8ff8
|
@@ -19,7 +19,7 @@ module CI
|
|
19
19
|
@global_max_requeues = (tests.size * requeue_tolerance).ceil
|
20
20
|
@shutdown_required = false
|
21
21
|
super(redis: redis, build_id: build_id)
|
22
|
-
@worker_id = worker_id
|
22
|
+
@worker_id = worker_id.to_s
|
23
23
|
@timeout = timeout
|
24
24
|
push(tests)
|
25
25
|
end
|
@@ -69,47 +69,38 @@ module CI
|
|
69
69
|
]
|
70
70
|
end
|
71
71
|
|
72
|
-
def acknowledge(test
|
73
|
-
|
74
|
-
|
75
|
-
else
|
76
|
-
raise ReservationError, "Acknowledged #{test.inspect} but #{@reserved_test.inspect} was reserved"
|
77
|
-
end
|
78
|
-
|
79
|
-
if !success && should_requeue?(test)
|
80
|
-
requeue(test)
|
81
|
-
false
|
82
|
-
else
|
83
|
-
ack(test)
|
84
|
-
true
|
85
|
-
end
|
72
|
+
def acknowledge(test)
|
73
|
+
raise_on_mismatching_test(test)
|
74
|
+
ack(test)
|
86
75
|
end
|
87
76
|
|
88
|
-
|
77
|
+
REQUEUE = %{
|
78
|
+
local processed_key = KEYS[1]
|
79
|
+
local requeues_count_key = KEYS[2]
|
80
|
+
local queue_key = KEYS[3]
|
81
|
+
local zset_key = KEYS[4]
|
89
82
|
|
90
|
-
|
83
|
+
local max_requeues = tonumber(ARGV[1])
|
84
|
+
local global_max_requeues = tonumber(ARGV[2])
|
85
|
+
local test = ARGV[3]
|
86
|
+
local offset = ARGV[4]
|
91
87
|
|
92
|
-
|
93
|
-
|
94
|
-
redis.hincrby(key('requeues-count'), test, 1)
|
95
|
-
redis.hincrby(key('requeues-count'), '___total___'.freeze, 1)
|
88
|
+
if redis.call('sismember', processed_key, test) == 1 then
|
89
|
+
return false
|
96
90
|
end
|
97
91
|
|
98
|
-
|
99
|
-
|
100
|
-
redis.hincrby(key('requeues-count'), test, -1)
|
101
|
-
redis.hincrby(key('requeues-count'), '___total___'.freeze, -1)
|
102
|
-
end
|
92
|
+
local global_requeues = tonumber(redis.call('hget', requeues_count_key, '___total___'))
|
93
|
+
if global_requeues and global_requeues >= tonumber(global_max_requeues) then
|
103
94
|
return false
|
104
95
|
end
|
105
96
|
|
106
|
-
|
107
|
-
|
97
|
+
local requeues = tonumber(redis.call('hget', requeues_count_key, test))
|
98
|
+
if requeues and requeues >= max_requeues then
|
99
|
+
return false
|
100
|
+
end
|
108
101
|
|
109
|
-
|
110
|
-
|
111
|
-
local test = ARGV[1]
|
112
|
-
local offset = ARGV[2]
|
102
|
+
redis.call('hincrby', requeues_count_key, '___total___', 1)
|
103
|
+
redis.call('hincrby', requeues_count_key, test, 1)
|
113
104
|
|
114
105
|
local pivot = redis.call('lrange', queue_key, -1 - offset, 0 - offset)[1]
|
115
106
|
if pivot then
|
@@ -117,14 +108,33 @@ module CI
|
|
117
108
|
else
|
118
109
|
redis.call('lpush', queue_key, test)
|
119
110
|
end
|
111
|
+
|
112
|
+
redis.call('zrem', zset_key, test)
|
113
|
+
|
114
|
+
return true
|
120
115
|
}
|
121
116
|
def requeue(test, offset: Redis.requeue_offset)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
117
|
+
raise_on_mismatching_test(test)
|
118
|
+
|
119
|
+
requeued = eval_script(
|
120
|
+
REQUEUE,
|
121
|
+
keys: [key('processed'), key('requeues-count'), key('queue'), key('running')],
|
122
|
+
argv: [max_requeues, global_max_requeues, test, offset],
|
123
|
+
) == 1
|
124
|
+
|
125
|
+
@reserved_test = test unless requeued
|
126
|
+
requeued
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
attr_reader :worker_id, :timeout, :max_requeues, :global_max_requeues
|
132
|
+
|
133
|
+
def raise_on_mismatching_test(test)
|
134
|
+
if @reserved_test == test
|
135
|
+
@reserved_test = nil
|
136
|
+
else
|
137
|
+
raise ReservationError, "Acknowledged #{test.inspect} but #{@reserved_test.inspect} was reserved"
|
128
138
|
end
|
129
139
|
end
|
130
140
|
|
@@ -140,6 +150,8 @@ module CI
|
|
140
150
|
RESERVE_TEST = %{
|
141
151
|
local queue_key = KEYS[1]
|
142
152
|
local zset_key = KEYS[2]
|
153
|
+
local processed_key = KEYS[3]
|
154
|
+
|
143
155
|
local current_time = ARGV[1]
|
144
156
|
|
145
157
|
local test = redis.call('rpop', queue_key)
|
@@ -151,38 +163,54 @@ module CI
|
|
151
163
|
end
|
152
164
|
}
|
153
165
|
def try_to_reserve_test
|
154
|
-
eval_script(
|
166
|
+
eval_script(
|
167
|
+
RESERVE_TEST,
|
168
|
+
keys: [key('queue'), key('running'), key('processed')],
|
169
|
+
argv: [Time.now.to_f],
|
170
|
+
)
|
155
171
|
end
|
156
172
|
|
157
173
|
RESERVE_LOST_TEST = %{
|
158
174
|
local zset_key = KEYS[1]
|
175
|
+
local processed_key = KEYS[2]
|
159
176
|
local current_time = ARGV[1]
|
160
177
|
local timeout = ARGV[2]
|
161
178
|
|
162
|
-
local
|
163
|
-
|
164
|
-
redis.call('
|
165
|
-
|
166
|
-
|
167
|
-
|
179
|
+
local lost_tests = redis.call('zrangebyscore', zset_key, 0, current_time - timeout)
|
180
|
+
for _, test in ipairs(lost_tests) do
|
181
|
+
if redis.call('sismember', processed_key, test) == 0 then
|
182
|
+
redis.call('zadd', zset_key, current_time, test)
|
183
|
+
return test
|
184
|
+
end
|
168
185
|
end
|
186
|
+
|
187
|
+
return nil
|
169
188
|
}
|
170
189
|
def try_to_reserve_lost_test
|
171
|
-
eval_script(
|
190
|
+
eval_script(
|
191
|
+
RESERVE_LOST_TEST,
|
192
|
+
keys: [key('running'), key('completed')],
|
193
|
+
argv: [Time.now.to_f, timeout],
|
194
|
+
)
|
172
195
|
end
|
173
196
|
|
174
197
|
ACKNOWLEDGE = %{
|
175
198
|
local zset_key = KEYS[1]
|
176
|
-
local
|
177
|
-
local test = ARGV[1]
|
199
|
+
local processed_key = KEYS[2]
|
178
200
|
|
179
|
-
|
180
|
-
|
181
|
-
|
201
|
+
local worker_id = ARGV[1]
|
202
|
+
local test = ARGV[2]
|
203
|
+
|
204
|
+
redis.call('zrem', zset_key, test)
|
205
|
+
return redis.call('sadd', processed_key, test)
|
182
206
|
}
|
183
207
|
def ack(test)
|
184
|
-
eval_script(ACKNOWLEDGE, keys: [key('running'), key('processed')], argv: [test])
|
185
208
|
redis.lpush(key('worker', worker_id, 'queue'), test)
|
209
|
+
eval_script(
|
210
|
+
ACKNOWLEDGE,
|
211
|
+
keys: [key('running'), key('processed')],
|
212
|
+
argv: [worker_id, test],
|
213
|
+
) == 1
|
186
214
|
end
|
187
215
|
|
188
216
|
def push(tests)
|
data/lib/ci/queue/static.rb
CHANGED
@@ -30,12 +30,14 @@ module CI
|
|
30
30
|
@queue.empty?
|
31
31
|
end
|
32
32
|
|
33
|
-
def acknowledge(test
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
33
|
+
def acknowledge(test)
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def requeue(test)
|
38
|
+
return false unless should_requeue?(test)
|
39
|
+
requeues[test] += 1
|
40
|
+
@queue.unshift(test)
|
39
41
|
true
|
40
42
|
end
|
41
43
|
|
@@ -47,11 +49,6 @@ module CI
|
|
47
49
|
requeues[test] < max_requeues && requeues.values.inject(0, :+) < global_max_requeues
|
48
50
|
end
|
49
51
|
|
50
|
-
def requeue(test)
|
51
|
-
requeues[test] += 1
|
52
|
-
@queue.unshift(test)
|
53
|
-
end
|
54
|
-
|
55
52
|
def requeues
|
56
53
|
@requeues ||= Hash.new(0)
|
57
54
|
end
|
data/lib/ci/queue/version.rb
CHANGED
data/lib/minitest/queue.rb
CHANGED
@@ -88,10 +88,15 @@ module Minitest
|
|
88
88
|
|
89
89
|
if klass = runnable_classes[class_name]
|
90
90
|
result = Minitest.run_one_method(klass, method_name)
|
91
|
-
|
91
|
+
failed = !(result.passed? || result.skipped?)
|
92
|
+
if failed && queue.requeue(test_name)
|
92
93
|
result.requeue!
|
94
|
+
reporter.record(result)
|
95
|
+
elsif queue.acknowledge(test_name) || !failed
|
96
|
+
# If the test was already acknowledged by another worker (we timed out)
|
97
|
+
# Then we only record it if it is successful.
|
98
|
+
reporter.record(result)
|
93
99
|
end
|
94
|
-
reporter.record(result)
|
95
100
|
else
|
96
101
|
raise SuiteNotFound, "Couldn't find suite matching: #{test_name}"
|
97
102
|
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.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -147,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
147
|
version: '0'
|
148
148
|
requirements: []
|
149
149
|
rubyforge_project:
|
150
|
-
rubygems_version: 2.
|
150
|
+
rubygems_version: 2.2.3
|
151
151
|
signing_key:
|
152
152
|
specification_version: 4
|
153
153
|
summary: Distribute tests over many workers using a queue
|