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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1042e561166bf47c7938f8d372d6ff1b69e6cdf999577b44e3c4a2ac3326cf1
4
- data.tar.gz: 983e5f31909dca78405b16208064460f830048c9a277fdbc76f9a4b5b8ea194c
3
+ metadata.gz: d89345ee8de2c77b0083cd7c93eb4aff552d57a298f6c0f55953093e5c69bd98
4
+ data.tar.gz: c41fac4baeaebe950d1f72fc69647b4aeca870b31bdd8b595cb821f1cea4bce5
5
5
  SHA512:
6
- metadata.gz: 89613e228c2b8bc014c25125eb65db6bd60816397b6e6df712e433d7901f4b21bd1b9444d73e8583d63209baeee513aca5e75f4c6a554008d9b78be0ac1bc9aa
7
- data.tar.gz: fa149f59031bc460de0395bc1c5b768129f741ba4a646b6772049be60fb491e04df9584c8ba42293b88810c35180559b33292922fa855d9380d33873a9672978
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,7 @@
1
+ module Reqless::JobReservers
2
+ module Strategies
3
+ require 'reqless/job_reservers/strategies/filtering'
4
+ require 'reqless/job_reservers/strategies/ordering'
5
+ require 'reqless/job_reservers/strategies/sources'
6
+ end
7
+ 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
@@ -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
- dqueues = client.queue_patterns.get_queue_identifier_patterns
607
- dqueues.each do |k, v|
608
- expanded = expand_queues(["@#{k}"], real_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,
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Reqless
4
4
  # VERSION is overwritten dynamically as part of the release process.
5
- VERSION = '0.0.4'
5
+ VERSION = '0.0.5'
6
6
  end
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
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-28 00:00:00.000000000 Z
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