qmore 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,7 +8,7 @@ module Qmore
8
8
  def self.registered(app)
9
9
 
10
10
  app.helpers do
11
-
11
+
12
12
  def qmore_view(filename, options = {}, locals = {})
13
13
  options = {:layout => true, :locals => { :title => filename.to_s.capitalize }}.merge(options)
14
14
  dir = File.expand_path("../server/views/", __FILE__)
@@ -24,7 +24,7 @@ module Qmore
24
24
  queue_tab_index = original_tabs.index {|t| t[:name] == 'Queues' }
25
25
  original_tabs.insert(queue_tab_index + 1, *qmore_tabs)
26
26
  end
27
-
27
+
28
28
  end
29
29
 
30
30
  #
@@ -34,7 +34,11 @@ module Qmore
34
34
  app.get "/dynamicqueues" do
35
35
  @queues = []
36
36
  real_queues = Qmore.client.queues.counts.collect {|q| q['name'] }
37
- dqueues = Attr.get_dynamic_queues
37
+
38
+ # For the UI we always want the latest persisted data
39
+ configuration = Qmore.persistence.load
40
+
41
+ dqueues = configuration.dynamic_queues
38
42
  dqueues.each do |k, v|
39
43
  expanded = Attr.expand_queues(["@#{k}"], real_queues)
40
44
  expanded = expanded.collect { |q| q.split(":").last }
@@ -69,7 +73,14 @@ module Qmore
69
73
  values = queue['value'].to_s.split(',').collect { |q| q.gsub(/\s/, '') }
70
74
  queues[key] = values
71
75
  end
72
- Attr.set_dynamic_queues(queues)
76
+
77
+ # For the UI we always want the latest persisted data
78
+ configuration = Qmore.persistence.load
79
+ configuration.dynamic_queues = queues
80
+
81
+ Qmore.persistence.write(configuration)
82
+ Qmore.configuration.dynamic_queues = configuration.dynamic_queues
83
+
73
84
  redirect to("/dynamicqueues")
74
85
  end
75
86
 
@@ -78,16 +89,25 @@ module Qmore
78
89
  #
79
90
 
80
91
  app.get "/queuepriority" do
81
- @priorities = Attr.get_priority_buckets
92
+ # For the UI we always want the latest persisted data
93
+ configuration = Qmore.persistence.load
94
+
95
+ @priorities = configuration.priority_buckets
82
96
  qmore_view :priorities
83
97
  end
84
98
 
85
99
  app.post "/queuepriority" do
86
100
  priorities = params['priorities']
87
- Attr.set_priority_buckets priorities
101
+
102
+ # For the UI we always want the latest persisted data
103
+ configuration = Qmore.persistence.load
104
+ configuration.priority_buckets = priorities
105
+
106
+ Qmore.persistence.write(configuration)
107
+ Qmore.configuration.priority_buckets = configuration.priority_buckets
108
+
88
109
  redirect to("/queuepriority")
89
110
  end
90
-
91
111
  end
92
112
  end
93
113
  end
@@ -1,3 +1,3 @@
1
1
  module Qmore
2
- VERSION = "0.6.2"
2
+ VERSION = "0.6.3"
3
3
  end
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_dependency("qless", '~> 0.9')
24
24
  s.add_dependency("multi_json", '~> 1.7')
25
+ s.add_dependency("gem_logger")
25
26
 
26
27
  s.add_development_dependency('rake')
27
28
  s.add_development_dependency('rspec')
@@ -5,70 +5,12 @@ describe "Attributes" do
5
5
 
6
6
  before(:each) do
7
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
8
+ Qmore.configuration = Qmore::Configuration.new
67
9
 
10
+ @real_queues = ["high_x", "foo", "high_y", "superhigh_z"]
68
11
  end
69
12
 
70
13
  context "basic queue patterns" do
71
-
72
14
  it "can specify simple queues" do
73
15
  expand_queues(["foo"], @real_queues).should == ["foo"]
74
16
  expand_queues(["foo", "bar"], @real_queues).should == ["bar", "foo"]
@@ -92,23 +34,21 @@ describe "Attributes" do
92
34
  it "can blacklist queues with pattern" do
93
35
  expand_queues(["*", "!*high*"], @real_queues).should == ["foo"]
94
36
  end
95
-
96
37
  end
97
38
 
98
- context "redis backed queues" do
99
-
39
+ context "expanding queues" do
100
40
  it "can dynamically lookup queues" do
101
- set_dynamic_queue("mykey", ["foo", "bar"])
41
+ Qmore.configuration.dynamic_queues = {"mykey" => ["foo", "bar"]}
102
42
  expand_queues(["@mykey"], @real_queues).should == ["bar", "foo"]
103
43
  end
104
44
 
105
45
  it "can blacklist dynamic queues" do
106
- set_dynamic_queue("mykey", ["foo"])
46
+ Qmore.configuration.dynamic_queues["mykey"] = ["foo"]
107
47
  expand_queues(["*", "!@mykey"], @real_queues).should == ["high_x", "high_y", "superhigh_z"]
108
48
  end
109
49
 
110
50
  it "can blacklist dynamic queues with negation" do
111
- set_dynamic_queue("mykey", ["!foo", "high_x"])
51
+ Qmore.configuration.dynamic_queues["mykey"] = ["!foo", "high_x"]
112
52
  expand_queues(["!@mykey"], @real_queues).should == ["foo"]
113
53
  end
114
54
 
@@ -119,18 +59,19 @@ describe "Attributes" do
119
59
  end
120
60
 
121
61
  it "uses hostname as default key in dynamic queues" do
122
- host = `hostname`.chomp
123
- set_dynamic_queue(host, ["foo", "bar"])
62
+ host = Socket.gethostname
63
+ Qmore.configuration.dynamic_queues[host] = ["foo", "bar"]
64
+
124
65
  expand_queues(["@"], @real_queues).should == ["bar", "foo"]
125
66
  end
126
67
 
127
68
  it "can use wildcards in dynamic queues" do
128
- set_dynamic_queue("mykey", ["*high*", "!high_y"])
69
+ Qmore.configuration.dynamic_queues["mykey"] = ["*high*", "!high_y"]
129
70
  expand_queues(["@mykey"], @real_queues).should == ["high_x", "superhigh_z"]
130
71
  end
131
72
 
132
73
  it "falls back to default queues when missing" do
133
- set_dynamic_queue("default", ["foo", "bar"])
74
+ Qmore.configuration.dynamic_queues["default"] = ["foo", "bar"]
134
75
  expand_queues(["@mykey"], @real_queues).should == ["bar", "foo"]
135
76
  end
136
77
 
@@ -143,11 +84,9 @@ describe "Attributes" do
143
84
  @real_queues << "bar"
144
85
  expand_queues(["@mykey"], @real_queues).should == ["bar", "foo", "high_x", "high_y", "superhigh_z"]
145
86
  end
146
-
147
87
  end
148
88
 
149
89
  context "queue priorities" do
150
-
151
90
  it "should pick up all queues with default priority" do
152
91
  priority_buckets = [{'pattern' => 'default', 'fairly' => false}]
153
92
  prioritize_queues(priority_buckets, @real_queues).should == ["high_x", "foo", "high_y", "superhigh_z"]
@@ -229,7 +168,5 @@ describe "Attributes" do
229
168
  queues[5..-1].should == ["high_x", "foo", "high_y", "superhigh_z"]
230
169
  queues.should_not == others.sort + ["high_x", "foo", "high_y", "superhigh_z"]
231
170
  end
232
-
233
171
  end
234
-
235
172
  end
@@ -0,0 +1,112 @@
1
+ require "spec_helper"
2
+
3
+ describe "Qmore::LegacyConfiguration" do
4
+ it "should always have a fallback pattern" do
5
+ configuration = Qmore::LegacyConfiguration.new(Qmore.persistence)
6
+
7
+ configuration.dynamic_queues['default'].should == ['*']
8
+ end
9
+
10
+ it "should load the latest dynamic queues from persistence" do
11
+ configuration = Qmore::LegacyConfiguration.new(Qmore.persistence)
12
+ expected_configuration = Qmore::Configuration.new
13
+
14
+ expected_configuration.dynamic_queues["foo"] = ["bar"]
15
+ expected_configuration.dynamic_queues["baz"] = ["biz"]
16
+ Qmore.persistence.write(expected_configuration)
17
+ configuration.dynamic_queues.should == expected_configuration.dynamic_queues
18
+
19
+ expected_configuration.dynamic_queues["baz"] = []
20
+ Qmore.persistence.write(expected_configuration)
21
+ # Ensuring baz was removed
22
+ configuration.dynamic_queues.should == {"foo" => ["bar"], "default" => ["*"]}
23
+ configuration.dynamic_queues.should == expected_configuration.dynamic_queues
24
+ end
25
+
26
+ it "should load the latest priority buckets from persistence" do
27
+ configuration = Qmore::LegacyConfiguration.new(Qmore.persistence)
28
+ expected_configuration = Qmore::Configuration.new
29
+ expected_configuration.priority_buckets = [{'pattern' => 'foo', 'fairly' => 'false'}]
30
+
31
+ Qmore.persistence.write(expected_configuration)
32
+
33
+ configuration.priority_buckets.should == expected_configuration.priority_buckets
34
+ end
35
+ end
36
+
37
+ describe "Qmore::Configuration" do
38
+ before(:each) do
39
+ Qmore.client.redis.flushall
40
+ end
41
+
42
+ context "dynamic queues" do
43
+ it "should always have a fallback pattern" do
44
+ configuration = Qmore::Configuration.new
45
+
46
+ configuration.dynamic_queues['default'].should == ['*']
47
+ end
48
+
49
+ it "should default any unspecified keys to default pattern" do
50
+ configuration = Qmore::Configuration.new
51
+ configuration.dynamic_queues['foo'].should == ['*']
52
+
53
+ configuration.dynamic_queues[Qmore::Configuration::DYNAMIC_FALLBACK_KEY] = ["foo", "bar"]
54
+ configuration.dynamic_queues['foo'].should == ["foo", "bar"]
55
+ end
56
+
57
+ it "should allow setting single patterns" do
58
+ configuration = Qmore::Configuration.new
59
+
60
+ configuration.dynamic_queues['foo'].should == ['*']
61
+ configuration.dynamic_queues['foo'] = ['bar']
62
+ configuration.dynamic_queues['foo'].should == ['bar']
63
+ end
64
+
65
+ it "should allow changing the pattern of the fallback key" do
66
+ configuration = Qmore::Configuration.new
67
+ configuration.dynamic_queues[Qmore::Configuration::DYNAMIC_FALLBACK_KEY].should == ['*']
68
+ configuration.dynamic_queues[Qmore::Configuration::DYNAMIC_FALLBACK_KEY] = ['foo', 'bar']
69
+ configuration.dynamic_queues[Qmore::Configuration::DYNAMIC_FALLBACK_KEY].should == ['foo', 'bar']
70
+ end
71
+
72
+ it "should ignore mappings when setting empty value" do
73
+ configuration = Qmore::Configuration.new
74
+ configuration.dynamic_queues = {'foo' => ['bar'], 'baz' => ['boo']}
75
+ configuration.dynamic_queues.should == {'default' => ['*'], 'foo' => ['bar'], 'baz' => ['boo']}
76
+
77
+ configuration.dynamic_queues = {'foo' => [], 'baz' => ['boo']}
78
+ configuration.dynamic_queues.should == {'default' => ['*'], 'baz' => ['boo']}
79
+ configuration.dynamic_queues = {'baz' => nil}
80
+ configuration.dynamic_queues.should == {'default' => ['*']}
81
+
82
+ configuration.dynamic_queues = {'foo' => ['bar'], 'baz' => ['boo']}
83
+ configuration.dynamic_queues['foo'] = []
84
+ configuration.dynamic_queues.should == {'default' => ["*"], 'baz' => ['boo']}
85
+ configuration.dynamic_queues['baz'] = nil
86
+ configuration.dynamic_queues.should == {'default' => ['*']}
87
+ end
88
+ end
89
+
90
+ context "priority attributes" do
91
+ it "should have a default priority" do
92
+ configuration = Qmore::Configuration.new
93
+ configuration.priority_buckets.should == [{'pattern' => 'default'}]
94
+ end
95
+
96
+ it "can set priorities" do
97
+ expected_priority_buckets = [{'pattern' => 'foo', 'fairly' => 'false'},{'pattern' => 'default'}]
98
+ configuration = Qmore::Configuration.new
99
+ configuration.priority_buckets = [{'pattern' => 'foo', 'fairly' => 'false'}]
100
+ configuration.priority_buckets.should == expected_priority_buckets
101
+ end
102
+
103
+ it "can set priorities including default" do
104
+ expected_priority_buckets = [{'pattern' => 'foo', 'fairly' => false},
105
+ {'pattern' => 'default', 'fairly' => false},
106
+ {'pattern' => 'bar', 'fairly' => true}]
107
+ configuration = Qmore::Configuration.new
108
+ configuration.priority_buckets = expected_priority_buckets
109
+ configuration.priority_buckets.should == expected_priority_buckets
110
+ end
111
+ end
112
+ end
@@ -5,6 +5,7 @@ describe "JobReserver" do
5
5
 
6
6
  before(:each) do
7
7
  Qmore.client.redis.flushall
8
+ Qmore.configuration = Qmore::Configuration.new
8
9
  end
9
10
 
10
11
  context "multiple qless server environment" do
@@ -13,8 +14,8 @@ describe "JobReserver" do
13
14
  qless2 = Qless::Client.new(:redis => Redis.connect(:port => 6380))
14
15
  queue_a = qless1.queues["a"]
15
16
  queue_b = qless2.queues["b"]
16
- queue_a.put(SomeJob, [])
17
- queue_b.put(SomeJob, [])
17
+ queue_a.put(SomeJob, {})
18
+ queue_b.put(SomeJob, {})
18
19
 
19
20
  queue_a.length.should == 1
20
21
  queue_b.length.should == 1
@@ -39,12 +40,88 @@ describe "JobReserver" do
39
40
  end
40
41
 
41
42
  context "basic qless behavior still works" do
43
+ it "ignores queues that have no work available" do
44
+ no_work_queue = Qmore.client.queues['no-work']
45
+ has_work_queue = Qmore.client.queues['has-work']
46
+
47
+ no_work_queue.put(SomeJob, {})
48
+ has_work_queue.put(SomeJob, {})
49
+
50
+ # drain the no work queue
51
+ no_work_queue.pop
52
+
53
+ reserver = Qmore::JobReserver.new([no_work_queue, has_work_queue])
54
+
55
+ queues = reserver.extract_queues(Qmore.client, ["*"]).collect(&:name)
56
+ queues.should include("has-work")
57
+ queues.should_not include("no-work")
58
+ end
59
+
60
+ it "should not ignore queues that have work in scheduled state" do
61
+ work_queue = Qmore.client.queues['work']
62
+ work_queue.put(SomeJob, {}, {:delay => 1600})
63
+
64
+ %w(waiting recurring depends stalled).each do |state|
65
+ work_queue.counts[state].should equal(0)
66
+ end
67
+ work_queue.counts["scheduled"].should equal(1)
68
+
69
+ reserver = Qmore::JobReserver.new([work_queue])
70
+ queues = reserver.extract_queues(Qmore.client, ["*"]).collect(&:name)
71
+ queues.should include("work")
72
+ end
73
+
74
+ it "should not ignore queues that have work in the depends state" do
75
+ work_queue = Qmore.client.queues['work']
76
+ jid = work_queue.put(SomeJob, {})
77
+ work_queue.put(SomeJob, {}, {:depends => [jid]})
78
+
79
+ work_queue.pop
80
+
81
+ %w(waiting recurring stalled scheduled).each do |state|
82
+ work_queue.counts[state].should equal(0)
83
+ end
84
+ work_queue.counts["depends"].should equal(1)
85
+
86
+ reserver = Qmore::JobReserver.new([work_queue])
87
+ queues = reserver.extract_queues(Qmore.client, ["*"]).collect(&:name)
88
+ queues.should include("work")
89
+ end
90
+
91
+ it "should not ignore queues that have work in the recurring state" do
92
+ work_queue = Qmore.client.queues['work']
93
+ work_queue.recur(SomeJob, {}, 1000)
94
+
95
+ %w(waiting depends stalled scheduled).each do |state|
96
+ work_queue.counts[state].should equal(0)
97
+ end
98
+ work_queue.counts["recurring"].should equal(1)
99
+
100
+ reserver = Qmore::JobReserver.new([work_queue])
101
+ queues = reserver.extract_queues(Qmore.client, ["*"]).collect(&:name)
102
+ queues.should include("work")
103
+ end
104
+
105
+ it "should not ignore queues that have work in the waiting state" do
106
+ work_queue = Qmore.client.queues['work']
107
+ work_queue.put(SomeJob, {})
108
+
109
+ %w(recurring depends stalled scheduled).each do |state|
110
+ work_queue.counts[state].should equal(0)
111
+ end
112
+ work_queue.counts["waiting"].should equal(1)
113
+
114
+ reserver = Qmore::JobReserver.new([work_queue])
115
+ queues = reserver.extract_queues(Qmore.client, ["*"]).collect(&:name)
116
+ queues.should include("work")
117
+ end
118
+
42
119
  it "can reserve from multiple queues" do
43
120
  high_queue = Qmore.client.queues['high']
44
121
  critical_queue = Qmore.client.queues['critical']
45
122
 
46
- high_queue.put(SomeJob, [])
47
- critical_queue.put(SomeJob, [])
123
+ high_queue.put(SomeJob, {})
124
+ critical_queue.put(SomeJob, {})
48
125
 
49
126
  reserver = Qmore::JobReserver.new([critical_queue, high_queue])
50
127
 
@@ -55,8 +132,8 @@ describe "JobReserver" do
55
132
  it "can work on multiple queues" do
56
133
  high_queue = Qmore.client.queues['high']
57
134
  critical_queue = Qmore.client.queues['critical']
58
- high_queue.put(SomeJob, [])
59
- critical_queue.put(SomeJob, [])
135
+ high_queue.put(SomeJob, {})
136
+ critical_queue.put(SomeJob, {})
60
137
 
61
138
  high_queue.length.should == 1
62
139
  critical_queue.length.should == 1
@@ -75,7 +152,7 @@ describe "JobReserver" do
75
152
  queues = []
76
153
  ['high', 'critical', 'blahblah'].each do |q|
77
154
  queue = Qmore.client.queues[q]
78
- queue.put(SomeJob, [])
155
+ queue.put(SomeJob, {})
79
156
  queue.length.should == 1
80
157
  queues << queue
81
158
  end
@@ -91,7 +168,7 @@ describe "JobReserver" do
91
168
  end
92
169
 
93
170
  it "handles priorities" do
94
- set_priority_buckets [{'pattern' => 'foo*', 'fairly' => false},
171
+ Qmore.configuration.priority_buckets = [{'pattern' => 'foo*', 'fairly' => false},
95
172
  {'pattern' => 'default', 'fairly' => false},
96
173
  {'pattern' => 'bar', 'fairly' => true}]
97
174
 
@@ -99,7 +176,7 @@ describe "JobReserver" do
99
176
  queues = []
100
177
  ['other', 'blah', 'foobie', 'bar', 'foo'].each do |q|
101
178
  queue = Qmore.client.queues[q]
102
- queue.put(SomeJob, [])
179
+ queue.put(SomeJob, {})
103
180
  queue.length.should == 1
104
181
  queues << queue
105
182
  end