reqless 0.0.4 → 0.0.5
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/reqless/job_reservers/delegating.rb +30 -0
- data/lib/reqless/job_reservers/strategies/filtering.rb +42 -0
- data/lib/reqless/job_reservers/strategies/ordering.rb +31 -0
- data/lib/reqless/job_reservers/strategies/sources.rb +63 -0
- data/lib/reqless/job_reservers/strategies.rb +7 -0
- data/lib/reqless/queue_patterns_helper.rb +113 -0
- data/lib/reqless/server.rb +6 -57
- data/lib/reqless/version.rb +1 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d89345ee8de2c77b0083cd7c93eb4aff552d57a298f6c0f55953093e5c69bd98
|
4
|
+
data.tar.gz: c41fac4baeaebe950d1f72fc69647b4aeca870b31bdd8b595cb821f1cea4bce5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b60f2d5e8d40f41179b418a09397dd2669126c351108fffc3781907793e3b4dee25dfa970b0bed8de2e7c05466bd1d10d1b53e0b4bb5b5f891327e8b63c688f2
|
7
|
+
data.tar.gz: 8afc28f017ec955c72994a1eeca4f7402c294603ab8a62ef991c1955a763614e66f3cdf0567728a80eeb45b6eeecbe3511c114e277bedde338ebf88bb82a476b
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Reqless::JobReservers
|
2
|
+
# @param [Enumerable] reservers - a set of reservers
|
3
|
+
# to check for work.
|
4
|
+
class Delegating < Struct.new(:reservers)
|
5
|
+
def description
|
6
|
+
"Delegating Reserver"
|
7
|
+
end
|
8
|
+
|
9
|
+
def prep_for_work!
|
10
|
+
# nothing here on purpose
|
11
|
+
end
|
12
|
+
|
13
|
+
def queues
|
14
|
+
Enumerator.new do |yielder|
|
15
|
+
reservers.each do |reserver|
|
16
|
+
reserver.queues.each {|queue| yielder << queue}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def reserve
|
22
|
+
reservers.each do |reserver|
|
23
|
+
if (job = reserver.reserve)
|
24
|
+
return job
|
25
|
+
end
|
26
|
+
end
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'reqless/queue_patterns_helper'
|
2
|
+
|
3
|
+
module Reqless
|
4
|
+
module JobReservers
|
5
|
+
module Strategies
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Reqless::JobReservers::Strategies::Filtering
|
11
|
+
# @param [Enumerable] queues - a source of queues
|
12
|
+
# @param [Array] regexes - a list of regexes to match against.
|
13
|
+
# Return an enumerator of the filtered queues in
|
14
|
+
# in prioritized order.
|
15
|
+
def self.default(
|
16
|
+
queues,
|
17
|
+
regexes,
|
18
|
+
queue_identifier_patterns,
|
19
|
+
queue_priority_patterns
|
20
|
+
)
|
21
|
+
Enumerator.new do |yielder|
|
22
|
+
# Map queues to their names
|
23
|
+
mapped_queues = queues.reduce({}) do |hash,queue|
|
24
|
+
hash[queue.name] = queue
|
25
|
+
hash
|
26
|
+
end
|
27
|
+
|
28
|
+
# Filter the queue names against the regexes provided.
|
29
|
+
matches = Reqless::QueuePatternsHelper.expand_queues(regexes, mapped_queues.keys, queue_identifier_patterns)
|
30
|
+
|
31
|
+
# Prioritize the queues.
|
32
|
+
prioritized_names = Reqless::QueuePatternsHelper.prioritize_queues(queue_priority_patterns, matches)
|
33
|
+
|
34
|
+
prioritized_names.each do |name|
|
35
|
+
queue = mapped_queues[name]
|
36
|
+
if queue
|
37
|
+
yielder << queue
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Reqless
|
2
|
+
module JobReservers
|
3
|
+
module Strategies
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Reqless::JobReservers::Strategies::Ordering
|
9
|
+
# Shuffles the underlying enumerable
|
10
|
+
# for each iteration.
|
11
|
+
# @param [Enumerable] enumerable - underlying enumerator to iterate over
|
12
|
+
def self.shuffled(enumerable)
|
13
|
+
Enumerator.new do |yielder|
|
14
|
+
enumerable.to_a.shuffle.each do |e|
|
15
|
+
yielder << e
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Samples a subset of the underlying enumerable
|
21
|
+
# for each iteration.
|
22
|
+
# @param [Enumerable] enumerable - underlying enumerator to iterate over
|
23
|
+
# @param [Integer] sample_size - number of items to take per iteration
|
24
|
+
def self.sampled(enumerable, sample_size = 5)
|
25
|
+
Enumerator.new do |yielder|
|
26
|
+
enumerable.to_a.sample(sample_size).each do |e|
|
27
|
+
yielder << e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Reqless
|
2
|
+
module JobReservers
|
3
|
+
module Strategies
|
4
|
+
end
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# This module provides the different kinds of queue sources used by qmore
|
9
|
+
module Reqless::JobReservers::Strategies::Sources
|
10
|
+
# Direct source uses a client to generate the queues we should
|
11
|
+
# pull work from. Ignores any queues that do not have tasks available.
|
12
|
+
def self.direct(client)
|
13
|
+
Enumerator.new do |yielder|
|
14
|
+
queues = client.queues.counts.select do |queue|
|
15
|
+
%w(waiting recurring depends stalled scheduled).any? {|state| queue[state].to_i > 0 }
|
16
|
+
end
|
17
|
+
|
18
|
+
queues.each do |queue|
|
19
|
+
yielder << client.queues[queue['name']]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Background Queue source runs in a background thread
|
25
|
+
# to periodically update the queues available.
|
26
|
+
class Background
|
27
|
+
include Enumerable
|
28
|
+
attr_reader :delegate, :delay
|
29
|
+
# @param [Enumerator] delegate queue source to load the queues from.
|
30
|
+
# @param [Integer] delay - how long between updates
|
31
|
+
def initialize(delegate, delay)
|
32
|
+
@delegate = delegate
|
33
|
+
@delay = delay
|
34
|
+
end
|
35
|
+
|
36
|
+
# Spawns a thread to periodically update the
|
37
|
+
# queues.
|
38
|
+
# @return [Thread] returns the spawned thread.
|
39
|
+
def start
|
40
|
+
@stop = false
|
41
|
+
@queues = delegate.to_a
|
42
|
+
Thread.new do
|
43
|
+
begin
|
44
|
+
loop do
|
45
|
+
sleep delay
|
46
|
+
break if @stop
|
47
|
+
@queues = delegate.to_a
|
48
|
+
end
|
49
|
+
rescue => e
|
50
|
+
retry
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def stop
|
56
|
+
@stop = true
|
57
|
+
end
|
58
|
+
|
59
|
+
def each(&block)
|
60
|
+
@queues.each { |q| block.call(q) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Reqless
|
2
|
+
module QueuePatternsHelper
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# Returns a list of queues to use when searching for a job.
|
6
|
+
#
|
7
|
+
# A splat ("*") means you want every queue (in alpha order) - this
|
8
|
+
# can be useful for dynamically adding new queues.
|
9
|
+
#
|
10
|
+
# The splat can also be used as a wildcard within a queue name,
|
11
|
+
# e.g. "*high*", and negation can be indicated with a prefix of "!"
|
12
|
+
#
|
13
|
+
# An @key can be used to dynamically look up the queue list for key from redis.
|
14
|
+
# If no key is supplied, it defaults to the worker's hostname, and wildcards
|
15
|
+
# and negations can be used inside this dynamic queue list.
|
16
|
+
def expand_queues(queue_patterns, real_queues, queue_identifier_patterns)
|
17
|
+
queue_patterns = queue_patterns.dup
|
18
|
+
real_queues = real_queues.dup
|
19
|
+
|
20
|
+
matched_queues = []
|
21
|
+
|
22
|
+
while q = queue_patterns.shift
|
23
|
+
q = q.to_s
|
24
|
+
negated = false
|
25
|
+
|
26
|
+
if q =~ /^(!)?@(.*)/
|
27
|
+
key = $2.strip
|
28
|
+
key = Socket.gethostname if key.size == 0
|
29
|
+
|
30
|
+
add_queues = queue_identifier_patterns.fetch(key, nil) ||
|
31
|
+
queue_identifier_patterns.fetch('default', ['*'])
|
32
|
+
add_queues = add_queues.map { |q| q.gsub!(/^!/, '') || q.gsub!(/^/, '!') } if $1
|
33
|
+
|
34
|
+
queue_patterns.concat(add_queues)
|
35
|
+
next
|
36
|
+
end
|
37
|
+
|
38
|
+
if q =~ /^!/
|
39
|
+
negated = true
|
40
|
+
q = q[1..-1]
|
41
|
+
end
|
42
|
+
|
43
|
+
patstr = q.gsub(/\*/, ".*")
|
44
|
+
pattern = /^#{patstr}$/
|
45
|
+
if negated
|
46
|
+
matched_queues -= matched_queues.grep(pattern)
|
47
|
+
else
|
48
|
+
matches = real_queues.grep(/^#{pattern}$/)
|
49
|
+
matches = [q] if matches.size == 0 && q == patstr
|
50
|
+
matched_queues.concat(matches)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return matched_queues.uniq.sort
|
55
|
+
end
|
56
|
+
|
57
|
+
def prioritize_queues(priority_buckets, real_queues)
|
58
|
+
real_queues = real_queues.dup
|
59
|
+
priority_buckets = priority_buckets.dup
|
60
|
+
|
61
|
+
result = []
|
62
|
+
default_idx = -1
|
63
|
+
default_fairly = false
|
64
|
+
|
65
|
+
# Walk the priority patterns, extract each into its own bucket
|
66
|
+
priority_buckets.each do |bucket|
|
67
|
+
bucket_pattern = bucket.pattern
|
68
|
+
fairly = bucket.should_distribute_fairly
|
69
|
+
|
70
|
+
# note the position of the default bucket for inserting the remaining queues at that location
|
71
|
+
if bucket_pattern == ['default']
|
72
|
+
default_idx = result.size
|
73
|
+
default_fairly = fairly
|
74
|
+
next
|
75
|
+
end
|
76
|
+
|
77
|
+
bucket_queues, remaining = [], []
|
78
|
+
|
79
|
+
bucket_pattern.each do |pattern|
|
80
|
+
pattern = pattern.strip
|
81
|
+
|
82
|
+
if pattern =~ /^!/
|
83
|
+
negated = true
|
84
|
+
pattern = pattern[1..-1]
|
85
|
+
end
|
86
|
+
|
87
|
+
patstr = pattern.gsub(/\*/, ".*")
|
88
|
+
pattern = /^#{patstr}$/
|
89
|
+
|
90
|
+
if negated
|
91
|
+
bucket_queues -= bucket_queues.grep(pattern)
|
92
|
+
else
|
93
|
+
bucket_queues.concat(real_queues.grep(pattern))
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
bucket_queues.uniq!
|
99
|
+
bucket_queues.shuffle! if fairly
|
100
|
+
real_queues = real_queues - bucket_queues
|
101
|
+
|
102
|
+
result << bucket_queues
|
103
|
+
end
|
104
|
+
|
105
|
+
# insert the remaining queues at the position the default item was at (or last)
|
106
|
+
real_queues.shuffle! if default_fairly
|
107
|
+
result.insert(default_idx, real_queues)
|
108
|
+
result.flatten!
|
109
|
+
|
110
|
+
return result
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/reqless/server.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'sinatra/base'
|
4
4
|
require 'reqless'
|
5
|
+
require 'reqless/queue_patterns_helper'
|
5
6
|
|
6
7
|
module Reqless
|
7
8
|
# The Reqless web interface
|
@@ -158,60 +159,6 @@ module Reqless
|
|
158
159
|
formatted
|
159
160
|
end
|
160
161
|
end
|
161
|
-
|
162
|
-
# Returns a list of queues to use when searching for a job.
|
163
|
-
#
|
164
|
-
# A splat ("*") means you want every queue (in alpha order) - this
|
165
|
-
# can be useful for dynamically adding new queues.
|
166
|
-
#
|
167
|
-
# The splat can also be used as a wildcard within a queue name,
|
168
|
-
# e.g. "*high*", and negation can be indicated with a prefix of "!"
|
169
|
-
#
|
170
|
-
# An @key can be used to dynamically look up the queue list for key from redis.
|
171
|
-
# If no key is supplied, it defaults to the worker's hostname, and wildcards
|
172
|
-
# and negations can be used inside this dynamic queue list. Set the queue
|
173
|
-
# list for a key with set_dynamic_queue(key, ["q1", "q2"]
|
174
|
-
#
|
175
|
-
def expand_queues(queue_patterns, real_queues)
|
176
|
-
queue_patterns = queue_patterns.dup
|
177
|
-
real_queues = real_queues.dup
|
178
|
-
dynamic_queues = client.queue_patterns.get_queue_identifier_patterns
|
179
|
-
|
180
|
-
matched_queues = []
|
181
|
-
|
182
|
-
while q = queue_patterns.shift
|
183
|
-
q = q.to_s
|
184
|
-
negated = false
|
185
|
-
|
186
|
-
if q =~ /^(!)?@(.*)/
|
187
|
-
key = $2.strip
|
188
|
-
key = Socket.gethostname if key.size == 0
|
189
|
-
|
190
|
-
add_queues = dynamic_queues[key]
|
191
|
-
add_queues.map! { |q| q.gsub!(/^!/, '') || q.gsub!(/^/, '!') } if $1
|
192
|
-
|
193
|
-
queue_patterns.concat(add_queues)
|
194
|
-
next
|
195
|
-
end
|
196
|
-
|
197
|
-
if q =~ /^!/
|
198
|
-
negated = true
|
199
|
-
q = q[1..-1]
|
200
|
-
end
|
201
|
-
|
202
|
-
patstr = q.gsub(/\*/, ".*")
|
203
|
-
pattern = /^#{patstr}$/
|
204
|
-
if negated
|
205
|
-
matched_queues -= matched_queues.grep(pattern)
|
206
|
-
else
|
207
|
-
matches = real_queues.grep(/^#{pattern}$/)
|
208
|
-
matches = [q] if matches.size == 0 && q == patstr
|
209
|
-
matched_queues.concat(matches)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
return matched_queues.uniq.sort
|
214
|
-
end
|
215
162
|
end
|
216
163
|
|
217
164
|
get '/?' do
|
@@ -603,9 +550,11 @@ module Reqless
|
|
603
550
|
@queues = []
|
604
551
|
real_queues = client.queues.counts.collect {|q| q['name'] }
|
605
552
|
|
606
|
-
|
607
|
-
|
608
|
-
expanded = expand_queues(
|
553
|
+
queue_identifier_patterns = client.queue_patterns.get_queue_identifier_patterns
|
554
|
+
queue_identifier_patterns.each do |k, v|
|
555
|
+
expanded = QueuePatternsHelper.expand_queues(
|
556
|
+
["@#{k}"], real_queues, queue_identifier_patterns
|
557
|
+
)
|
609
558
|
expanded = expanded.collect { |q| q.split(":").last }
|
610
559
|
view_data = {
|
611
560
|
'name' => k,
|
data/lib/reqless/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: reqless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Lecocq
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-08-
|
13
|
+
date: 2024-08-29 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: redis
|
@@ -303,9 +303,14 @@ files:
|
|
303
303
|
- lib/reqless/config.rb
|
304
304
|
- lib/reqless/failure_formatter.rb
|
305
305
|
- lib/reqless/job.rb
|
306
|
+
- lib/reqless/job_reservers/delegating.rb
|
306
307
|
- lib/reqless/job_reservers/ordered.rb
|
307
308
|
- lib/reqless/job_reservers/round_robin.rb
|
308
309
|
- lib/reqless/job_reservers/shuffled_round_robin.rb
|
310
|
+
- lib/reqless/job_reservers/strategies.rb
|
311
|
+
- lib/reqless/job_reservers/strategies/filtering.rb
|
312
|
+
- lib/reqless/job_reservers/strategies/ordering.rb
|
313
|
+
- lib/reqless/job_reservers/strategies/sources.rb
|
309
314
|
- lib/reqless/lua/reqless-lib.lua
|
310
315
|
- lib/reqless/lua/reqless.lua
|
311
316
|
- lib/reqless/lua_script.rb
|
@@ -314,6 +319,7 @@ files:
|
|
314
319
|
- lib/reqless/middleware/sentry.rb
|
315
320
|
- lib/reqless/middleware/timeout.rb
|
316
321
|
- lib/reqless/queue.rb
|
322
|
+
- lib/reqless/queue_patterns_helper.rb
|
317
323
|
- lib/reqless/queue_priority_pattern.rb
|
318
324
|
- lib/reqless/server.rb
|
319
325
|
- lib/reqless/server/static/css/bootstrap-responsive.css
|