ci-queue 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|