resque-dynamic-queues 0.6.1 → 0.7.0

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ 0.7.0
2
+ -----
3
+
4
+ api breaking refactor, web ui improvements <51948a0> [Matt Conway]
5
+ add rackup config for testing web ui <009ccda> [Matt Conway]
6
+
1
7
  0.6.1
2
8
  -----
3
9
 
data/config.ru ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'logger'
3
+
4
+ $LOAD_PATH.unshift ::File.expand_path(::File.dirname(__FILE__) + '/lib')
5
+ require 'resque/server'
6
+ require 'resque-dynamic-queues-server'
7
+
8
+ use Rack::ShowExceptions
9
+ run Resque::Server.new
@@ -1,2 +1,4 @@
1
1
  require 'resque-dynamic-queues'
2
- require 'resque/plugins/dynamic_queues/server'
2
+ require 'resque/plugins/dynamic_queues/server'
3
+
4
+ Resque::Server.register Resque::Plugins::DynamicQueues::Server
@@ -2,40 +2,50 @@ module Resque
2
2
  module Plugins
3
3
  module DynamicQueues
4
4
 
5
- KEY_PREFIX = "dynamic_queue"
5
+ DYNAMIC_QUEUE_KEY = "dynamic_queue"
6
6
  FALLBACK_KEY = "default"
7
7
 
8
8
  module Attributes
9
9
 
10
- def get_dynamic_queue(key)
11
- queue_names = redis.lrange("#{KEY_PREFIX}:#{key}", 0, -1)
10
+ def get_dynamic_queue(key, fallback=['*'])
11
+ data = redis.hget(DYNAMIC_QUEUE_KEY, key)
12
+ queue_names = Resque.decode(data)
12
13
 
13
14
  if queue_names.nil? || queue_names.size == 0
14
- queue_names = redis.lrange("#{KEY_PREFIX}:#{FALLBACK_KEY}", 0, -1)
15
+ data = redis.hget(DYNAMIC_QUEUE_KEY, FALLBACK_KEY)
16
+ queue_names = Resque.decode(data)
15
17
  end
16
18
 
17
19
  if queue_names.nil? || queue_names.size == 0
18
- queue_names = Resque.queues
20
+ queue_names = fallback
19
21
  end
20
22
 
21
23
  return queue_names
22
24
  end
23
25
 
24
26
  def set_dynamic_queue(key, values)
25
- k = "#{KEY_PREFIX}:#{key}"
27
+ if values.nil? or values.size == 0
28
+ redis.hdel(DYNAMIC_QUEUE_KEY, key)
29
+ else
30
+ redis.hset(DYNAMIC_QUEUE_KEY, key, Resque.encode(values))
31
+ end
32
+ end
33
+
34
+ def set_dynamic_queues(dynamic_queues)
26
35
  redis.multi do
27
- redis.del(k)
28
- Array(values).each do |v|
29
- redis.rpush(k, v)
36
+ redis.del(DYNAMIC_QUEUE_KEY)
37
+ dynamic_queues.each do |k, v|
38
+ set_dynamic_queue(k, v)
30
39
  end
31
40
  end
32
41
  end
33
42
 
34
43
  def get_dynamic_queues
35
- dqueues = redis.keys("#{KEY_PREFIX}:*") || []
36
- dqueues = dqueues.collect{|q| q.gsub('dynamic_queue:', '')}
37
- dqueues << FALLBACK_KEY unless dqueues.include?(FALLBACK_KEY)
38
- return dqueues
44
+ result = {}
45
+ queues = redis.hgetall(DYNAMIC_QUEUE_KEY)
46
+ queues.each {|k, v| result[k] = Resque.decode(v) }
47
+ result[FALLBACK_KEY] ||= ['*']
48
+ return result
39
49
  end
40
50
 
41
51
  end
@@ -9,25 +9,46 @@ module Resque
9
9
 
10
10
  def self.registered(app)
11
11
  app.get "/dynamicqueues" do
12
- @queues = Resque.get_dynamic_queues
13
- dq_view :queues
12
+ @queues = []
13
+ dqueues = Resque.get_dynamic_queues
14
+ dqueues.each do |k, v|
15
+ view_data = {
16
+ 'name' => k,
17
+ 'value' => Array(v).join(", "),
18
+ 'expanded' => Resque::Worker.new("@#{k}").queues.join(", ")
19
+ }
20
+ @queues << view_data
21
+ end
22
+
23
+ @queues.sort! do |a, b|
24
+ an = a['name']
25
+ bn = b['name']
26
+ if an == 'default'
27
+ 1
28
+ elsif bn == 'default'
29
+ -1
30
+ else
31
+ an <=> bn
32
+ end
33
+ end
34
+
35
+ plugin_view :queues
14
36
  end
15
37
 
16
38
  app.post "/dynamicqueues" do
17
- key = params['name']
18
- values = params['queues'].to_s.split.collect{|q| q.gsub(/\s/, '')}
19
- Resque.set_dynamic_queue(key, values)
20
- redirect url(:dynamicqueues)
21
- end
22
-
23
- app.post "/dynamicqueues/:key/remove" do
24
- key = params['key']
25
- Resque.set_dynamic_queue(key, [])
39
+ dynamic_queues = Array(params['queues'])
40
+ queues = {}
41
+ dynamic_queues.each do |queue|
42
+ key = queue['name']
43
+ values = queue['value'].to_s.split(',').collect{|q| q.gsub(/\s/, '') }
44
+ queues[key] = values
45
+ end
46
+ Resque.set_dynamic_queues(queues)
26
47
  redirect url(:dynamicqueues)
27
48
  end
28
49
 
29
50
  app.helpers do
30
- def dq_view(filename, options = {}, locals = {})
51
+ def plugin_view(filename, options = {}, locals = {})
31
52
  erb(File.read(File.join(::Resque::Plugins::DynamicQueues::Server::VIEW_PATH, "#{filename}.erb")), options, locals)
32
53
  end
33
54
  end
@@ -38,5 +59,3 @@ module Resque
38
59
  end
39
60
  end
40
61
  end
41
-
42
- Resque::Server.register Resque::Plugins::DynamicQueues::Server
@@ -1,58 +1,61 @@
1
1
  <h1>Dynamic Queues</h1>
2
- <table class='workers'>
3
- <tr>
4
- <th>Name</th>
5
- <th>Value</th>
6
- <th>Result</th>
7
- <th>Workers</th>
8
- <th></th>
9
- </tr>
10
- <% @queues.each do |queue| %>
2
+ <p class="intro">
3
+ 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 '*'
4
+ </p>
5
+
6
+ <form action="<%= url(:dynamicqueues) %>" method="POST" style="float:none; margin-top:10px">
7
+
8
+ <table class='queues'>
11
9
  <tr>
12
- <td><%= queue %></td>
13
- <td><%= Resque.get_dynamic_queue(queue).join(", ") %></td>
14
- <td><%= Resque::Worker.new("@#{queue}").queues.join(", ") %></td>
15
- <td></td>
16
- <td>
17
- <a href="<%= url(:dynamicqueues) %>/<%= queue %>/remove" class="remove">Remove</a>
18
- </td>
10
+ <th>Name</th>
11
+ <th>Value</th>
12
+ <th>Expanded</th>
13
+ <th></th>
19
14
  </tr>
20
- <% end %>
21
- </table>
22
-
23
-
24
- <h1>Make a new queue</h1>
25
- <form action="<%= url(:dynamicqueues) %>" method="post" accept-charset="utf-8">
26
- <p><input type="text" name="name"></p>
27
- <p>
28
- <textarea name="queues"></textarea>
29
- Separate new queues by lines
30
- </p>
31
- <p><input type="submit" value="Create or Update"></p>
32
- </form>
15
+ <% @queues.each_with_index do |data, i| %>
16
+ <tr class="line">
17
+ <td><input type="text" id="input-<%= i %>-name" name="queues[][name]" value="<%= data['name'] %>" /></td>
18
+ <td><input type="text" id="input-<%= i %>-value" name="queues[][value]" value="<%= data['value'] %>" /></td>
19
+ <td class="expanded"><%= data['expanded'] %></td>
20
+ <td>
21
+ <a href="#remove" class="remove">Remove</a>
22
+ </td>
23
+ </tr>
24
+ <% end %>
25
+ </table>
26
+
27
+ <a href="#add" class="add">Add</a>
28
+ <input type="submit" value="Save"/>
33
29
 
30
+ </form>
34
31
 
35
32
  <script type="text/javascript" charset="utf-8">
33
+ function markDirty()
34
+ {
35
+ $("input[type=submit]").css({border:"3px orange solid"});
36
+ }
37
+
36
38
  jQuery(function($) {
37
39
 
38
- $('a.remove').click(function(e) {
40
+ $("input").live("keypress", markDirty);
41
+
42
+ $("a.add").live("click", function(e) {
43
+ e.preventDefault();
44
+ var $table = $("table.queues");
45
+ var $newRow = $table.find("tr.line:first").clone();
46
+ $newRow.find("input[type=text]").attr("value", "");
47
+ $newRow.find("td.expanded").html("")
48
+ $newRow.appendTo($table);
49
+ markDirty();
50
+ });
51
+
52
+ $("a.remove").live("click", function(e) {
39
53
  e.preventDefault();
40
- var $link = $(this),
41
- url = $link.attr('href'),
42
- confirmed = confirm("Are you sure you want to remove this dynamic queue? There is no undo.");
43
- if (confirmed) {
44
- $link.animate({opacity: 0.5});
45
- $.ajax({
46
- url: url,
47
- type: 'post',
48
- success: function() {
49
- $link.parents('tr').remove();
50
- }
51
- });
52
- } else {
53
- return false
54
- }
54
+ var $link = $(this);
55
+ $link.parents("tr").remove();
56
+ markDirty();
55
57
  });
56
58
 
59
+
57
60
  });
58
61
  </script>
@@ -1,7 +1,7 @@
1
1
  module Resque
2
2
  module Plugins
3
3
  module DynamicQueues
4
- VERSION = "0.6.1"
4
+ VERSION = "0.7.0"
5
5
  end
6
6
  end
7
7
  end
data/spec/queues_spec.rb CHANGED
@@ -55,6 +55,42 @@ describe "Dynamic Queues" do
55
55
 
56
56
  end
57
57
 
58
+ context "attributes" do
59
+ it "should always have a fallback pattern" do
60
+ Resque.get_dynamic_queues.should == {'default' => ['*']}
61
+ end
62
+
63
+ it "should allow setting single patterns" do
64
+ Resque.get_dynamic_queue('foo').should == ['*']
65
+ Resque.set_dynamic_queue('foo', ['bar'])
66
+ Resque.get_dynamic_queue('foo').should == ['bar']
67
+ end
68
+
69
+ it "should allow setting multiple patterns" do
70
+ Resque.set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
71
+ Resque.get_dynamic_queues.should == {'foo' => ['bar'], 'baz' => ['boo'], 'default' => ['*']}
72
+ end
73
+
74
+ it "should remove mapping when setting empty value" do
75
+ Resque.get_dynamic_queues
76
+ Resque.set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
77
+ Resque.get_dynamic_queues.should == {'foo' => ['bar'], 'baz' => ['boo'], 'default' => ['*']}
78
+
79
+ Resque.set_dynamic_queues({'foo' => [], 'baz' => ['boo']})
80
+ Resque.get_dynamic_queues.should == {'baz' => ['boo'], 'default' => ['*']}
81
+ Resque.set_dynamic_queues({'baz' => nil})
82
+ Resque.get_dynamic_queues.should == {'default' => ['*']}
83
+
84
+ Resque.set_dynamic_queues({'foo' => ['bar'], 'baz' => ['boo']})
85
+ Resque.set_dynamic_queue('foo', [])
86
+ Resque.get_dynamic_queues.should == {'baz' => ['boo'], 'default' => ['*']}
87
+ Resque.set_dynamic_queue('baz', nil)
88
+ Resque.get_dynamic_queues.should == {'default' => ['*']}
89
+ end
90
+
91
+
92
+ end
93
+
58
94
  context "basic queue patterns" do
59
95
 
60
96
  before(:each) do
data/spec/server_spec.rb CHANGED
@@ -37,6 +37,12 @@ describe "Dynamic Queues pages" do
37
37
 
38
38
  context "show dynamic queues table" do
39
39
 
40
+ it "should shows default queue when nothing set" do
41
+ get "/dynamicqueues"
42
+
43
+ last_response.body.should include 'default'
44
+ end
45
+
40
46
  it "should shows names of queues" do
41
47
  Resque.set_dynamic_queue("key_one", ["foo"])
42
48
  Resque.set_dynamic_queue("key_two", ["bar"])
@@ -61,23 +67,18 @@ describe "Dynamic Queues pages" do
61
67
 
62
68
  context "remove queue link" do
63
69
 
64
-
65
- it "should shows remove link for queue" do
70
+ it "should show remove link for queue" do
66
71
  Resque.set_dynamic_queue("key_one", ["foo"])
67
72
 
68
73
  get "/dynamicqueues"
69
74
 
70
- last_response.body.should match /<a .*href=['"]http:\/\/example.org\/dynamicqueues\/key_one\/remove['"].*>/
75
+ last_response.body.should match /<a .*href=['"]#remove['"].*>/
71
76
  end
72
77
 
73
- it "should remove queue when remove link clicked" do # JS will do the post
74
- Resque.set_dynamic_queue("key_one", ["foo"])
75
-
76
- post "/dynamicqueues/key_one/remove"
78
+ it "should show add link" do
79
+ get "/dynamicqueues"
77
80
 
78
- last_response.should be_redirect
79
- last_response['Location'].should match /dynamicqueues/
80
- Resque.get_dynamic_queue("key_two").should be_empty
81
+ last_response.body.should match /<a .*href=['"]#add['"].*>/
81
82
  end
82
83
 
83
84
  end
@@ -87,22 +88,31 @@ describe "Dynamic Queues pages" do
87
88
  it "should have form to edit queues" do
88
89
  get "/dynamicqueues"
89
90
 
90
- last_response.body.should match /<form .*action=['"]http:\/\/example.org\/dynamicqueues['"].*>/
91
- last_response.body.should match /<input .*name=['"]name['"].*>/
92
- last_response.body.should match /<textarea .*name=['"]queues['"].*>/
91
+ last_response.body.should match /<form action="http:\/\/example.org\/dynamicqueues"/
92
+ end
93
+
94
+ it "should show input fields" do
95
+ Resque.set_dynamic_queue("key_one", ["foo"])
96
+ Resque.set_dynamic_queue("key_two", ["bar", "baz"])
97
+ get "/dynamicqueues"
98
+
99
+ last_response.body.should match /<input type="text" id="input-0-name" name="queues\[\]\[name\]" value="key_one"/
100
+ last_response.body.should match /<input type="text" id="input-0-value" name="queues\[\]\[value\]" value="foo"/
101
+ last_response.body.should match /<input type="text" id="input-1-name" name="queues\[\]\[name\]" value="key_two"/
102
+ last_response.body.should match /<input type="text" id="input-1-value" name="queues\[\]\[value\]" value="bar, baz"/
93
103
  end
94
104
 
95
105
  it "should delete queues on empty queue submit" do
96
106
  Resque.set_dynamic_queue("key_two", ["bar", "baz"])
97
- post "/dynamicqueues", {'name' => "key_two", "queues" => ""}
107
+ post "/dynamicqueues", {'queues' => [{'name' => "key_two", "value" => ""}]}
98
108
 
99
109
  last_response.should be_redirect
100
110
  last_response['Location'].should match /dynamicqueues/
101
- Resque.get_dynamic_queue("key_two").should be_empty
111
+ Resque.get_dynamic_queue("key_two", []).should be_empty
102
112
  end
103
113
 
104
114
  it "should create queues" do
105
- post "/dynamicqueues", {'name' => "key_two", "queues" => "foo\n\rbar\n\rbaz"}
115
+ post "/dynamicqueues", {'queues' => [{'name' => "key_two", "value" => " foo, bar ,baz "}]}
106
116
 
107
117
  last_response.should be_redirect
108
118
  last_response['Location'].should match /dynamicqueues/
@@ -111,7 +121,7 @@ describe "Dynamic Queues pages" do
111
121
 
112
122
  it "should update queues" do
113
123
  Resque.set_dynamic_queue("key_two", ["bar", "baz"])
114
- post "/dynamicqueues", {'name' => "key_two", "queues" => "foo\n\rbar\n\rbaz"}
124
+ post "/dynamicqueues", {'queues' => [{'name' => "key_two", "value" => "foo,bar,baz"}]}
115
125
 
116
126
  last_response.should be_redirect
117
127
  last_response['Location'].should match /dynamicqueues/
@@ -120,4 +130,4 @@ describe "Dynamic Queues pages" do
120
130
 
121
131
  end
122
132
 
123
- end
133
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-dynamic-queues
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-07 00:00:00.000000000Z
12
+ date: 2011-12-13 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: resque
16
- requirement: &2176833480 !ruby/object:Gem::Requirement
16
+ requirement: &2236617460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '1.10'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2176833480
24
+ version_requirements: *2236617460
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2176808620 !ruby/object:Gem::Requirement
27
+ requirement: &2236616960 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '2.5'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2176808620
35
+ version_requirements: *2236616960
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rack-test
38
- requirement: &2176798820 !ruby/object:Gem::Requirement
38
+ requirement: &2236616500 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 0.5.4
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2176798820
46
+ version_requirements: *2236616500
47
47
  description: A resque plugin for specifying the queues a worker pulls from with wildcards,
48
48
  negations, or dynamic look up from redis
49
49
  email:
@@ -57,6 +57,7 @@ files:
57
57
  - Gemfile
58
58
  - README.md
59
59
  - Rakefile
60
+ - config.ru
60
61
  - init.rb
61
62
  - lib/resque-dynamic-queues-server.rb
62
63
  - lib/resque-dynamic-queues.rb