qmore 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/.travis.yml +5 -0
- data/CHANGELOG +4 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.md +118 -0
- data/Rakefile +2 -0
- data/config.ru +8 -0
- data/lib/qmore-server.rb +5 -0
- data/lib/qmore.rb +22 -0
- data/lib/qmore/attributes.rb +191 -0
- data/lib/qmore/job_reserver.rb +37 -0
- data/lib/qmore/server.rb +93 -0
- data/lib/qmore/server/views/dynamicqueues.erb +64 -0
- data/lib/qmore/server/views/priorities.erb +78 -0
- data/lib/qmore/version.rb +3 -0
- data/qmore.gemspec +33 -0
- data/spec/attributes_spec.rb +235 -0
- data/spec/job_reserver_spec.rb +87 -0
- data/spec/redis-test.conf +312 -0
- data/spec/server_spec.rb +237 -0
- data/spec/spec_helper.rb +49 -0
- metadata +172 -0
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
<div class="page-header">
|
3
|
+
<h1>Dynamic Queues</h1>
|
4
|
+
</div>
|
5
|
+
<p class="intro">
|
6
|
+
The list below shows the dynamic queues currently defined. When you start a worker with a dynamic queue key (@key_name), that key is looked up from the list below to determine the actual queues the worker should pull from. Wildcards (*) and negation (leading !) can be used to select the queues the worker should process. There is always a fallback key - @default, which workers will use if the key for that worker is empty. If both the key and the fallback are empty, the worker defaults to processing '*'
|
7
|
+
</p>
|
8
|
+
|
9
|
+
<form action="/dynamicqueues" method="POST" style="float:none; margin-top:10px">
|
10
|
+
|
11
|
+
<table class='queues'>
|
12
|
+
<tr>
|
13
|
+
<th>Name</th>
|
14
|
+
<th>Value</th>
|
15
|
+
<th>Expanded</th>
|
16
|
+
<th></th>
|
17
|
+
</tr>
|
18
|
+
<% @queues.each_with_index do |data, i| %>
|
19
|
+
<tr class="line">
|
20
|
+
<td><input type="text" id="input-<%= i %>-name" name="queues[][name]" value="<%= data['name'] %>" /></td>
|
21
|
+
<td><input type="text" id="input-<%= i %>-value" name="queues[][value]" value="<%= data['value'] %>" /></td>
|
22
|
+
<td class="expanded"><%= data['expanded'] %></td>
|
23
|
+
<td>
|
24
|
+
<a href="#remove" class="remove">Remove</a>
|
25
|
+
</td>
|
26
|
+
</tr>
|
27
|
+
<% end %>
|
28
|
+
</table>
|
29
|
+
|
30
|
+
<a href="#add" class="add">Add</a>
|
31
|
+
<input type="submit" value="Save"/>
|
32
|
+
|
33
|
+
</form>
|
34
|
+
|
35
|
+
<script type="text/javascript" charset="utf-8">
|
36
|
+
function markDirty()
|
37
|
+
{
|
38
|
+
$("input[type=submit]").css({border:"3px orange solid"});
|
39
|
+
}
|
40
|
+
|
41
|
+
jQuery(function($) {
|
42
|
+
|
43
|
+
$("input").live("keypress", markDirty);
|
44
|
+
|
45
|
+
$("a.add").live("click", function(e) {
|
46
|
+
e.preventDefault();
|
47
|
+
var $table = $("table.queues");
|
48
|
+
var $newRow = $table.find("tr.line:first").clone();
|
49
|
+
$newRow.find("input[type=text]").attr("value", "");
|
50
|
+
$newRow.find("td.expanded").html("")
|
51
|
+
$newRow.appendTo($table);
|
52
|
+
markDirty();
|
53
|
+
});
|
54
|
+
|
55
|
+
$("a.remove").live("click", function(e) {
|
56
|
+
e.preventDefault();
|
57
|
+
var $link = $(this);
|
58
|
+
$link.parents("tr").remove();
|
59
|
+
markDirty();
|
60
|
+
});
|
61
|
+
|
62
|
+
|
63
|
+
});
|
64
|
+
</script>
|
@@ -0,0 +1,78 @@
|
|
1
|
+
<div class="page-header">
|
2
|
+
<h1>Queue Priority</h1>
|
3
|
+
</div>
|
4
|
+
<p class="intro">
|
5
|
+
The list below orders queue name patterns by the priority you wish them to be executed in. The "Fairly" option allows you to indicate you want the queues within that pattern space be selected in a fair (random) manner, i.e. like resque-fairly. The 'default' pattern must always exist, and matches against all queues that aren't in any of the other patterns.
|
6
|
+
</p>
|
7
|
+
|
8
|
+
<form action="/queuepriority" method="POST" style="float:none; margin-top:10px">
|
9
|
+
|
10
|
+
<table class="priorities">
|
11
|
+
<tr>
|
12
|
+
<th>Pattern</th>
|
13
|
+
<th>Fairly</th>
|
14
|
+
<th></th>
|
15
|
+
</tr>
|
16
|
+
<% @priorities.each_with_index do |priority, i| %>
|
17
|
+
<tr class="line">
|
18
|
+
<td><input type="text" id="input-<%= i %>-pattern" name="priorities[][pattern]" value="<%= priority["pattern"] %>" /></td>
|
19
|
+
<td><input type="checkbox" id="input-<%= i %>-fairly" name="priorities[][fairly]" value="true" <%= "checked" if priority["fairly"] %> /></td>
|
20
|
+
<td>
|
21
|
+
<a href="#up" class="up">Up</a> |
|
22
|
+
<a href="#down" class="down">Down</a> |
|
23
|
+
<a href="#remove" class="remove">Remove</a>
|
24
|
+
</td>
|
25
|
+
</tr>
|
26
|
+
<% end %>
|
27
|
+
</table>
|
28
|
+
|
29
|
+
<a href="#add" class="add">Add</a>
|
30
|
+
<input type="submit" value="Save"/>
|
31
|
+
|
32
|
+
</form>
|
33
|
+
|
34
|
+
<script type="text/javascript" charset="utf-8">
|
35
|
+
function markDirty()
|
36
|
+
{
|
37
|
+
$("input[type=submit]").css({border:"3px orange solid"});
|
38
|
+
}
|
39
|
+
|
40
|
+
jQuery(function($) {
|
41
|
+
$("input").live("keypress", markDirty);
|
42
|
+
$("input[type=checkbox]").live("click", markDirty);
|
43
|
+
|
44
|
+
$("a.add").live("click", function(e) {
|
45
|
+
e.preventDefault();
|
46
|
+
var $table = $("table.priorities");
|
47
|
+
var $newRow = $table.find("tr.line:first").clone();
|
48
|
+
$newRow.find("input[type=text]").attr("value", "");
|
49
|
+
$newRow.find("input[type=checkbox]").attr("checked", false);
|
50
|
+
$newRow.appendTo($table);
|
51
|
+
markDirty();
|
52
|
+
});
|
53
|
+
|
54
|
+
$("a.remove").live("click", function(e) {
|
55
|
+
e.preventDefault();
|
56
|
+
var $link = $(this);
|
57
|
+
$link.parents("tr").remove();
|
58
|
+
markDirty();
|
59
|
+
});
|
60
|
+
|
61
|
+
$("a.up").live("click", function(e) {
|
62
|
+
e.preventDefault();
|
63
|
+
var $link = $(this);
|
64
|
+
var $row = $link.parents("tr");
|
65
|
+
$row.prev(".line").before($row);
|
66
|
+
markDirty();
|
67
|
+
});
|
68
|
+
|
69
|
+
$("a.down").live("click", function(e) {
|
70
|
+
e.preventDefault();
|
71
|
+
var $link = $(this);
|
72
|
+
var $row = $link.parents("tr");
|
73
|
+
$row.next(".line").after($row);
|
74
|
+
markDirty();
|
75
|
+
});
|
76
|
+
|
77
|
+
});
|
78
|
+
</script>
|
data/qmore.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'qmore/version'
|
4
|
+
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "qmore"
|
8
|
+
s.version = Qmore::VERSION
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.authors = ["Matt Conway"]
|
11
|
+
s.email = ["matt@conwaysplace.com"]
|
12
|
+
s.homepage = ""
|
13
|
+
s.summary = %q{A qless plugin that gives more control over how queues are processed}
|
14
|
+
s.description = %q{Qmore allows one to specify the queues a worker processes by the use of wildcards, negations, or dynamic look up from redis. It also allows one to specify the relative priority between queues (rather than within a single queue). It plugs into the Qless webapp to make it easy to manage the queues.}
|
15
|
+
|
16
|
+
s.rubyforge_project = "qmore"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_dependency("qless", '~> 0.9.3')
|
24
|
+
s.add_dependency("multi_json", '~> 1.7.7')
|
25
|
+
|
26
|
+
s.add_development_dependency('rake')
|
27
|
+
s.add_development_dependency('rspec', '~> 2.5')
|
28
|
+
s.add_development_dependency('rack-test', '~> 0.5.4')
|
29
|
+
# Needed for correct ordering when passing hash params to rack-test
|
30
|
+
s.add_development_dependency('orderedhash')
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Attributes" do
|
4
|
+
include Qmore::Attributes
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Qmore.client.redis.flushall
|
8
|
+
@real_queues = ["high_x", "foo", "high_y", "superhigh_z"]
|
9
|
+
end
|
10
|
+
|
11
|
+
context "dynamic attributes" do
|
12
|
+
|
13
|
+
it "should always have a fallback pattern" do
|
14
|
+
get_dynamic_queues.should == {'default' => ['*']}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should allow setting single patterns" do
|
18
|
+
get_dynamic_queue('foo').should == ['*']
|
19
|
+
set_dynamic_queue('foo', ['bar'])
|
20
|
+
get_dynamic_queue('foo').should == ['bar']
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should allow setting multiple patterns" do
|
24
|
+
set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
|
25
|
+
get_dynamic_queues.should == {'foo' => ['bar'], 'baz' => ['boo'], 'default' => ['*']}
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should remove mapping when setting empty value" do
|
29
|
+
get_dynamic_queues
|
30
|
+
set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
|
31
|
+
get_dynamic_queues.should == {'foo' => ['bar'], 'baz' => ['boo'], 'default' => ['*']}
|
32
|
+
|
33
|
+
set_dynamic_queues({'foo' => [], 'baz' => ['boo']})
|
34
|
+
get_dynamic_queues.should == {'baz' => ['boo'], 'default' => ['*']}
|
35
|
+
set_dynamic_queues({'baz' => nil})
|
36
|
+
get_dynamic_queues.should == {'default' => ['*']}
|
37
|
+
|
38
|
+
set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
|
39
|
+
set_dynamic_queue('foo', [])
|
40
|
+
get_dynamic_queues.should == {'baz' => ['boo'], 'default' => ['*']}
|
41
|
+
set_dynamic_queue('baz', nil)
|
42
|
+
get_dynamic_queues.should == {'default' => ['*']}
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
context "priority attributes" do
|
48
|
+
|
49
|
+
it "can lookup a default priority" do
|
50
|
+
get_priority_buckets.should == [{'pattern' => 'default'}]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "can set priorities" do
|
54
|
+
set_priority_buckets [{'pattern' => 'foo', 'fairly' => 'false'}]
|
55
|
+
get_priority_buckets.should == [{'pattern' => 'foo', 'fairly' => 'false'},
|
56
|
+
{'pattern' => 'default'}]
|
57
|
+
end
|
58
|
+
|
59
|
+
it "can set priorities including default" do
|
60
|
+
set_priority_buckets [{'pattern' => 'foo', 'fairly' => false},
|
61
|
+
{'pattern' => 'default', 'fairly' => false},
|
62
|
+
{'pattern' => 'bar', 'fairly' => true}]
|
63
|
+
get_priority_buckets.should == [{'pattern' => 'foo', 'fairly' => false},
|
64
|
+
{'pattern' => 'default', 'fairly' => false},
|
65
|
+
{'pattern' => 'bar', 'fairly' => true}]
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
context "basic queue patterns" do
|
71
|
+
|
72
|
+
it "can specify simple queues" do
|
73
|
+
expand_queues(["foo"], @real_queues).should == ["foo"]
|
74
|
+
expand_queues(["foo", "bar"], @real_queues).should == ["bar", "foo"]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "can specify simple wildcard" do
|
78
|
+
worker = Qless::Worker.new("*")
|
79
|
+
expand_queues(["*"], @real_queues).should == ["foo", "high_x", "high_y", "superhigh_z"]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "can include queues with pattern" do
|
83
|
+
expand_queues(["high*"], @real_queues).should == ["high_x", "high_y"]
|
84
|
+
expand_queues(["*high_z"], @real_queues).should == ["superhigh_z"]
|
85
|
+
expand_queues(["*high*"], @real_queues).should == ["high_x", "high_y", "superhigh_z"]
|
86
|
+
end
|
87
|
+
|
88
|
+
it "can blacklist queues" do
|
89
|
+
expand_queues(["*", "!foo"], @real_queues).should == ["high_x", "high_y", "superhigh_z"]
|
90
|
+
end
|
91
|
+
|
92
|
+
it "can blacklist queues with pattern" do
|
93
|
+
expand_queues(["*", "!*high*"], @real_queues).should == ["foo"]
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
context "redis backed queues" do
|
99
|
+
|
100
|
+
it "can dynamically lookup queues" do
|
101
|
+
set_dynamic_queue("mykey", ["foo", "bar"])
|
102
|
+
expand_queues(["@mykey"], @real_queues).should == ["bar", "foo"]
|
103
|
+
end
|
104
|
+
|
105
|
+
it "can blacklist dynamic queues" do
|
106
|
+
set_dynamic_queue("mykey", ["foo"])
|
107
|
+
expand_queues(["*", "!@mykey"], @real_queues).should == ["high_x", "high_y", "superhigh_z"]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "can blacklist dynamic queues with negation" do
|
111
|
+
set_dynamic_queue("mykey", ["!foo", "high_x"])
|
112
|
+
expand_queues(["!@mykey"], @real_queues).should == ["foo"]
|
113
|
+
end
|
114
|
+
|
115
|
+
it "will not bloat the given real_queues" do
|
116
|
+
orig = @real_queues.dup
|
117
|
+
expand_queues(["@mykey"], @real_queues)
|
118
|
+
@real_queues.should == orig
|
119
|
+
end
|
120
|
+
|
121
|
+
it "uses hostname as default key in dynamic queues" do
|
122
|
+
host = `hostname`.chomp
|
123
|
+
set_dynamic_queue(host, ["foo", "bar"])
|
124
|
+
expand_queues(["@"], @real_queues).should == ["bar", "foo"]
|
125
|
+
end
|
126
|
+
|
127
|
+
it "can use wildcards in dynamic queues" do
|
128
|
+
set_dynamic_queue("mykey", ["*high*", "!high_y"])
|
129
|
+
expand_queues(["@mykey"], @real_queues).should == ["high_x", "superhigh_z"]
|
130
|
+
end
|
131
|
+
|
132
|
+
it "falls back to default queues when missing" do
|
133
|
+
set_dynamic_queue("default", ["foo", "bar"])
|
134
|
+
expand_queues(["@mykey"], @real_queues).should == ["bar", "foo"]
|
135
|
+
end
|
136
|
+
|
137
|
+
it "falls back to all queues when missing and no default" do
|
138
|
+
expand_queues(["@mykey"], @real_queues).should == ["foo", "high_x", "high_y", "superhigh_z"]
|
139
|
+
end
|
140
|
+
|
141
|
+
it "falls back to all queues when missing and no default and keep up to date" do
|
142
|
+
expand_queues(["@mykey"], @real_queues).should == ["foo", "high_x", "high_y", "superhigh_z"]
|
143
|
+
@real_queues << "bar"
|
144
|
+
expand_queues(["@mykey"], @real_queues).should == ["bar", "foo", "high_x", "high_y", "superhigh_z"]
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
context "queue priorities" do
|
150
|
+
|
151
|
+
it "should pick up all queues with default priority" do
|
152
|
+
priority_buckets = [{'pattern' => 'default', 'fairly' => false}]
|
153
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "foo", "high_y", "superhigh_z"]
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should pick up all queues fairly" do
|
157
|
+
# do a bunch to reduce likelyhood of random match causing test failure
|
158
|
+
@real_queues = 50.times.collect { |i| "auto_#{i}" }
|
159
|
+
priority_buckets = [{'pattern' => 'default', 'fairly' => true}]
|
160
|
+
prioritize_queues(priority_buckets, @real_queues).should_not == @real_queues.sort
|
161
|
+
prioritize_queues(priority_buckets, @real_queues).sort.should == @real_queues.sort
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should prioritize simple pattern" do
|
165
|
+
priority_buckets = [{'pattern' => 'superhigh_z', 'fairly' => false},
|
166
|
+
{'pattern' => 'default', 'fairly' => false}]
|
167
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["superhigh_z", "high_x", "foo", "high_y"]
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should prioritize multiple simple patterns" do
|
171
|
+
priority_buckets = [{'pattern' => 'superhigh_z', 'fairly' => false},
|
172
|
+
{'pattern' => 'default', 'fairly' => false},
|
173
|
+
{'pattern' => 'foo', 'fairly' => false}]
|
174
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["superhigh_z", "high_x", "high_y", "foo"]
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should prioritize simple wildcard pattern" do
|
178
|
+
priority_buckets = [{'pattern' => 'high*', 'fairly' => false},
|
179
|
+
{'pattern' => 'default', 'fairly' => false}]
|
180
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "high_y", "foo", "superhigh_z"]
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should prioritize simple wildcard pattern with correct matching" do
|
184
|
+
priority_buckets = [{'pattern' => '*high*', 'fairly' => false},
|
185
|
+
{'pattern' => 'default', 'fairly' => false}]
|
186
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "high_y", "superhigh_z", "foo"]
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should prioritize negation patterns" do
|
190
|
+
@real_queues.delete("high_x")
|
191
|
+
@real_queues << "high_x"
|
192
|
+
priority_buckets = [{'pattern' => 'high*,!high_x', 'fairly' => false},
|
193
|
+
{'pattern' => 'default', 'fairly' => false}]
|
194
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_y", "foo", "superhigh_z", "high_x"]
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should not be affected by standalone negation patterns" do
|
198
|
+
priority_buckets = [{'pattern' => '!high_x', 'fairly' => false},
|
199
|
+
{'pattern' => 'default', 'fairly' => false}]
|
200
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "foo", "high_y", "superhigh_z"]
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should allow multiple inclusive patterns" do
|
204
|
+
priority_buckets = [{'pattern' => 'high_x, superhigh*', 'fairly' => false},
|
205
|
+
{'pattern' => 'default', 'fairly' => false}]
|
206
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "superhigh_z", "foo", "high_y"]
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should prioritize fully inclusive wildcard pattern" do
|
210
|
+
priority_buckets = [{'pattern' => '*high*', 'fairly' => false},
|
211
|
+
{'pattern' => 'default', 'fairly' => false}]
|
212
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "high_y", "superhigh_z", "foo"]
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should handle empty default match" do
|
216
|
+
priority_buckets = [{'pattern' => '*', 'fairly' => false},
|
217
|
+
{'pattern' => 'default', 'fairly' => false}]
|
218
|
+
prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "foo", "high_y", "superhigh_z"]
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should pickup wildcard queues fairly" do
|
222
|
+
others = 5.times.collect { |i| "other#{i}" }
|
223
|
+
@real_queues = @real_queues + others
|
224
|
+
|
225
|
+
priority_buckets = [{'pattern' => 'other*', 'fairly' => true},
|
226
|
+
{'pattern' => 'default', 'fairly' => false}]
|
227
|
+
queues = prioritize_queues(priority_buckets, @real_queues)
|
228
|
+
queues[0..4].sort.should == others.sort
|
229
|
+
queues[5..-1].should == ["high_x", "foo", "high_y", "superhigh_z"]
|
230
|
+
queues.should_not == others.sort + ["high_x", "foo", "high_y", "superhigh_z"]
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "JobReserver" do
|
4
|
+
include Qmore::Attributes
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Qmore.client.redis.flushall
|
8
|
+
end
|
9
|
+
|
10
|
+
context "basic qless behavior still works" do
|
11
|
+
|
12
|
+
it "can reserve from multiple queues" do
|
13
|
+
high_queue = Qmore.client.queues['high']
|
14
|
+
critical_queue = Qmore.client.queues['critical']
|
15
|
+
|
16
|
+
high_queue.put(SomeJob, [])
|
17
|
+
critical_queue.put(SomeJob, [])
|
18
|
+
|
19
|
+
reserver = Qmore::JobReserver.new([critical_queue, high_queue])
|
20
|
+
reserver.reserve.queue.name.should == 'critical'
|
21
|
+
reserver.reserve.queue.name.should == 'high'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can work on multiple queues" do
|
25
|
+
high_queue = Qmore.client.queues['high']
|
26
|
+
critical_queue = Qmore.client.queues['critical']
|
27
|
+
high_queue.put(SomeJob, [])
|
28
|
+
critical_queue.put(SomeJob, [])
|
29
|
+
|
30
|
+
high_queue.length.should == 1
|
31
|
+
critical_queue.length.should == 1
|
32
|
+
|
33
|
+
reserver = Qmore::JobReserver.new([critical_queue, high_queue])
|
34
|
+
|
35
|
+
worker = Qless::Worker.new(reserver,
|
36
|
+
:run_as_single_process => true)
|
37
|
+
worker.work(0)
|
38
|
+
|
39
|
+
high_queue.length.should == 0
|
40
|
+
critical_queue.length.should == 0
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can work on all queues" do
|
44
|
+
queues = []
|
45
|
+
['high', 'critical', 'blahblah'].each do |q|
|
46
|
+
queue = Qmore.client.queues[q]
|
47
|
+
queue.put(SomeJob, [])
|
48
|
+
queue.length.should == 1
|
49
|
+
queues << queue
|
50
|
+
end
|
51
|
+
|
52
|
+
reserver = Qmore::JobReserver.new([Qmore.client.queues['*']])
|
53
|
+
worker = Qless::Worker.new(reserver,
|
54
|
+
:run_as_single_process => true)
|
55
|
+
worker.work(0)
|
56
|
+
|
57
|
+
queues.each do |q|
|
58
|
+
q.length.should == 0
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "handles priorities" do
|
63
|
+
set_priority_buckets [{'pattern' => 'foo*', 'fairly' => false},
|
64
|
+
{'pattern' => 'default', 'fairly' => false},
|
65
|
+
{'pattern' => 'bar', 'fairly' => true}]
|
66
|
+
|
67
|
+
|
68
|
+
queues = []
|
69
|
+
['other', 'blah', 'foobie', 'bar', 'foo'].each do |q|
|
70
|
+
queue = Qmore.client.queues[q]
|
71
|
+
queue.put(SomeJob, [])
|
72
|
+
queue.length.should == 1
|
73
|
+
queues << queue
|
74
|
+
end
|
75
|
+
|
76
|
+
reserver = Qmore::JobReserver.new([Qmore.client.queues['*'], Qmore.client.queues['!blah']])
|
77
|
+
|
78
|
+
reserver.reserve.queue.name.should == 'foo'
|
79
|
+
reserver.reserve.queue.name.should == 'foobie'
|
80
|
+
reserver.reserve.queue.name.should == 'other'
|
81
|
+
reserver.reserve.queue.name.should == 'bar'
|
82
|
+
reserver.reserve.should be_nil
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|