resque_sqs 1.25.2

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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +467 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +866 -0
  5. data/Rakefile +70 -0
  6. data/bin/resque-sqs +81 -0
  7. data/bin/resque-sqs-web +27 -0
  8. data/lib/resque_sqs/errors.rb +13 -0
  9. data/lib/resque_sqs/failure/airbrake.rb +33 -0
  10. data/lib/resque_sqs/failure/base.rb +73 -0
  11. data/lib/resque_sqs/failure/multiple.rb +59 -0
  12. data/lib/resque_sqs/failure/redis.rb +108 -0
  13. data/lib/resque_sqs/failure/redis_multi_queue.rb +89 -0
  14. data/lib/resque_sqs/failure.rb +113 -0
  15. data/lib/resque_sqs/helpers.rb +107 -0
  16. data/lib/resque_sqs/job.rb +346 -0
  17. data/lib/resque_sqs/log_formatters/quiet_formatter.rb +7 -0
  18. data/lib/resque_sqs/log_formatters/verbose_formatter.rb +7 -0
  19. data/lib/resque_sqs/log_formatters/very_verbose_formatter.rb +8 -0
  20. data/lib/resque_sqs/logging.rb +18 -0
  21. data/lib/resque_sqs/plugin.rb +66 -0
  22. data/lib/resque_sqs/server/helpers.rb +52 -0
  23. data/lib/resque_sqs/server/public/favicon.ico +0 -0
  24. data/lib/resque_sqs/server/public/idle.png +0 -0
  25. data/lib/resque_sqs/server/public/jquery-1.3.2.min.js +19 -0
  26. data/lib/resque_sqs/server/public/jquery.relatize_date.js +95 -0
  27. data/lib/resque_sqs/server/public/poll.png +0 -0
  28. data/lib/resque_sqs/server/public/ranger.js +78 -0
  29. data/lib/resque_sqs/server/public/reset.css +44 -0
  30. data/lib/resque_sqs/server/public/style.css +91 -0
  31. data/lib/resque_sqs/server/public/working.png +0 -0
  32. data/lib/resque_sqs/server/test_helper.rb +19 -0
  33. data/lib/resque_sqs/server/views/error.erb +1 -0
  34. data/lib/resque_sqs/server/views/failed.erb +29 -0
  35. data/lib/resque_sqs/server/views/failed_job.erb +50 -0
  36. data/lib/resque_sqs/server/views/failed_queues_overview.erb +24 -0
  37. data/lib/resque_sqs/server/views/key_sets.erb +19 -0
  38. data/lib/resque_sqs/server/views/key_string.erb +11 -0
  39. data/lib/resque_sqs/server/views/layout.erb +44 -0
  40. data/lib/resque_sqs/server/views/next_more.erb +22 -0
  41. data/lib/resque_sqs/server/views/overview.erb +4 -0
  42. data/lib/resque_sqs/server/views/queues.erb +58 -0
  43. data/lib/resque_sqs/server/views/stats.erb +62 -0
  44. data/lib/resque_sqs/server/views/workers.erb +109 -0
  45. data/lib/resque_sqs/server/views/working.erb +72 -0
  46. data/lib/resque_sqs/server.rb +271 -0
  47. data/lib/resque_sqs/stat.rb +57 -0
  48. data/lib/resque_sqs/tasks.rb +83 -0
  49. data/lib/resque_sqs/vendor/utf8_util/utf8_util_18.rb +91 -0
  50. data/lib/resque_sqs/vendor/utf8_util/utf8_util_19.rb +5 -0
  51. data/lib/resque_sqs/vendor/utf8_util.rb +20 -0
  52. data/lib/resque_sqs/version.rb +3 -0
  53. data/lib/resque_sqs/worker.rb +779 -0
  54. data/lib/resque_sqs.rb +479 -0
  55. data/lib/tasks/redis_sqs.rake +161 -0
  56. data/lib/tasks/resque_sqs.rake +2 -0
  57. data/test/airbrake_test.rb +27 -0
  58. data/test/failure_base_test.rb +15 -0
  59. data/test/job_hooks_test.rb +465 -0
  60. data/test/job_plugins_test.rb +230 -0
  61. data/test/logging_test.rb +24 -0
  62. data/test/plugin_test.rb +116 -0
  63. data/test/redis-test-cluster.conf +115 -0
  64. data/test/redis-test.conf +115 -0
  65. data/test/resque-web_test.rb +59 -0
  66. data/test/resque_failure_redis_test.rb +19 -0
  67. data/test/resque_hook_test.rb +165 -0
  68. data/test/resque_test.rb +278 -0
  69. data/test/stdout +42 -0
  70. data/test/test_helper.rb +228 -0
  71. data/test/worker_test.rb +1080 -0
  72. metadata +202 -0
@@ -0,0 +1,44 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <title>ResqueSqs.</title>
6
+ <link href="<%=u 'reset.css' %>" media="screen" rel="stylesheet" type="text/css">
7
+ <link href="<%=u 'style.css' %>" media="screen" rel="stylesheet" type="text/css">
8
+ <script src="<%=u 'jquery-1.3.2.min.js' %>" type="text/javascript"></script>
9
+ <script src="<%=u 'jquery.relatize_date.js' %>" type="text/javascript"></script>
10
+ <script src="<%=u 'ranger.js' %>" type="text/javascript"></script>
11
+ </head>
12
+ <body>
13
+ <div class="header">
14
+ <ul class='nav'>
15
+ <% tabs.each do |tab_name| %>
16
+ <%= tab tab_name %>
17
+ <% end %>
18
+ </ul>
19
+ <% if ResqueSqs.redis.namespace != :resque %>
20
+ <abbr class="namespace" title="Resque's Redis Namespace">
21
+ <%= ResqueSqs.redis.namespace %>
22
+ </abbr>
23
+ <% end %>
24
+ </div>
25
+
26
+ <% if @subtabs %>
27
+ <ul class='subnav'>
28
+ <% for subtab in @subtabs %>
29
+ <li <%= class_if_current "#{current_section}/#{subtab}" %>><a href="<%= current_section %>/<%= subtab %>"><span><%= subtab %></span></a></li>
30
+ <% end %>
31
+ </ul>
32
+ <% end %>
33
+
34
+ <div id="main">
35
+ <%= yield %>
36
+ </div>
37
+
38
+ <div id="footer">
39
+ <p>Powered by <a href="http://github.com/resque/resque">Resque</a> v<%=ResqueSqs::Version%></p>
40
+ <p>Connected to Redis namespace <%= ResqueSqs.redis.namespace %> on <%=ResqueSqs.redis_id%></p>
41
+ </div>
42
+
43
+ </body>
44
+ </html>
@@ -0,0 +1,22 @@
1
+ <% # per_page was added in 1.23.1; gems which add to resque-server don't pass that variable along so it would crash %>
2
+ <% # without a default value %>
3
+ <% per_page ||= 20 %>
4
+ <%if start - per_page >= 0 || start + per_page <= size%>
5
+ <p class='pagination'>
6
+ <% if start + per_page <= size %>
7
+ <a href="<%= current_page %>?start=<%= start + per_page %>" class='more'>&laquo; Next</a>
8
+ <% end %>
9
+
10
+ <% (size / per_page.to_f - 1).ceil.downto(0).each do |page_num| %>
11
+ <% if start == page_num * per_page %>
12
+ <%= page_num %>
13
+ <% else %>
14
+ <a href="<%= current_page %>?start=<%= page_num * per_page %>"> <%= page_num %></a>
15
+ <% end %>
16
+ <% end %>
17
+
18
+ <% if start - per_page >= 0 %>
19
+ <a href="<%= current_page %>?start=<%= start - per_page %>" class='less'>Previous &raquo;</a>
20
+ <% end %>
21
+ </p>
22
+ <%end%>
@@ -0,0 +1,4 @@
1
+ <%= partial :queues %>
2
+ <hr />
3
+ <%= partial :working %>
4
+ <%= poll %>
@@ -0,0 +1,58 @@
1
+ <% @subtabs = resque.queues unless partial? || params[:id].nil? %>
2
+
3
+ <% if queue = params[:id] %>
4
+
5
+ <h1>Pending jobs on <span class='hl'><%= queue %></span></h1>
6
+ <form method="POST" action="<%=u "/queues/#{queue}/remove" %>" class='remove-queue'>
7
+ <input type='submit' name='' value='Remove Queue' onclick='return confirm("Are you absolutely sure? This cannot be undone.");' />
8
+ </form>
9
+ <p class='sub'>Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = resque.size(queue)%></b> jobs</p>
10
+ <table class='jobs'>
11
+ <tr>
12
+ <th>Class</th>
13
+ <th>Args</th>
14
+ </tr>
15
+ <% for job in (jobs = resque.peek(queue, start, 20)) %>
16
+ <tr>
17
+ <td class='class'><%= job['class'] %></td>
18
+ <td class='args'><%=h job['args'].inspect %></td>
19
+ </tr>
20
+ <% end %>
21
+ <% if jobs.empty? %>
22
+ <tr>
23
+ <td class='no-data' colspan='2'>There are no pending jobs in this queue</td>
24
+ </tr>
25
+ <% end %>
26
+ </table>
27
+ <%= partial :next_more, :start => start, :size => size, :per_page => 20 %>
28
+ <% else %>
29
+
30
+ <h1 class='wi'>Queues</h1>
31
+ <p class='intro'>The list below contains all the registered queues with the number of jobs currently in the queue. Select a queue from above to view all jobs currently pending on the queue.</p>
32
+ <table class='queues'>
33
+ <tr>
34
+ <th>Name</th>
35
+ <th>Jobs</th>
36
+ </tr>
37
+ <% resque.queues.sort_by { |q| q.to_s }.each do |queue| %>
38
+ <tr>
39
+ <td class='queue'><a class="queue" href="<%= u "queues/#{queue}" %>"><%= queue %></a></td>
40
+ <td class='size'><%= resque.size queue %></td>
41
+ </tr>
42
+ <% end %>
43
+ <% if failed_multiple_queues? %>
44
+ <% ResqueSqs::Failure.queues.sort_by { |q| q.to_s }.each_with_index do |queue, i| %>
45
+ <tr class="<%= ResqueSqs::Failure.count(queue).zero? ? "failed" : "failure" %><%= " first_failure" if i.zero? %>">
46
+ <td class='queue failed'><a class="queue" href="<%= u "failed/#{queue}" %>"><%= queue %></a></td>
47
+ <td class='size'><%= ResqueSqs::Failure.count(queue) %></td>
48
+ </tr>
49
+ <% end %>
50
+ <% else %>
51
+ <tr class="<%= ResqueSqs::Failure.count.zero? ? "failed" : "failure" %>">
52
+ <td class='queue failed'><a class="queue" href="<%= u :failed %>">failed</a></td>
53
+ <td class='size'><%= ResqueSqs::Failure.count %></td>
54
+ </tr>
55
+ <% end %>
56
+ </table>
57
+
58
+ <% end %>
@@ -0,0 +1,62 @@
1
+ <% @subtabs = %w( resque redis keys ) %>
2
+
3
+ <% if params[:key] %>
4
+
5
+ <%= partial resque.redis.type(params[:key]).eql?("string") ? :key_string : :key_sets %>
6
+
7
+ <% elsif params[:id] == "resque" %>
8
+
9
+ <h1><%= resque %></h1>
10
+ <table class='stats'>
11
+ <% for key, value in resque.info.to_a.sort_by { |i| i[0].to_s } %>
12
+ <tr>
13
+ <th>
14
+ <%= key %>
15
+ </th>
16
+ <td>
17
+ <%= value %>
18
+ </td>
19
+ </tr>
20
+ <% end %>
21
+ </table>
22
+
23
+ <% elsif params[:id] == 'redis' %>
24
+
25
+ <h1><%= resque.redis_id %></h1>
26
+ <table class='stats'>
27
+ <% for key, value in resque.redis.info.to_a.sort_by { |i| i[0].to_s } %>
28
+ <tr>
29
+ <th>
30
+ <%= key %>
31
+ </th>
32
+ <td>
33
+ <%= value %>
34
+ </td>
35
+ </tr>
36
+ <% end %>
37
+ </table>
38
+
39
+ <% elsif params[:id] == 'keys' %>
40
+
41
+ <h1>Keys owned by <%= resque %></h1>
42
+ <p class='sub'>(All keys are actually prefixed with "<%= ResqueSqs.redis.namespace %>:")</p>
43
+ <table class='stats'>
44
+ <tr>
45
+ <th>key</th>
46
+ <th>type</th>
47
+ <th>size</th>
48
+ </tr>
49
+ <% for key in resque.keys.sort %>
50
+ <tr>
51
+ <th>
52
+ <a href="<%=u "/stats/keys/#{key}" %>"><%= key %></a>
53
+ </th>
54
+ <td><%= resque.redis.type key %></td>
55
+ <td><%= redis_get_size key %></td>
56
+ </tr>
57
+ <% end %>
58
+ </table>
59
+
60
+ <% else %>
61
+
62
+ <% end %>
@@ -0,0 +1,109 @@
1
+ <% @subtabs = worker_hosts.keys.sort unless worker_hosts.size == 1 %>
2
+
3
+ <% if params[:id] && worker = ResqueSqs::Worker.find(params[:id]) %>
4
+
5
+ <h1>Worker <%= worker %></h1>
6
+ <table class='workers'>
7
+ <tr>
8
+ <th>&nbsp;</th>
9
+ <th>Host</th>
10
+ <th>Pid</th>
11
+ <th>Started</th>
12
+ <th>Queues</th>
13
+ <th>Processed</th>
14
+ <th>Failed</th>
15
+ <th>Processing</th>
16
+ </tr>
17
+ <tr>
18
+ <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
19
+
20
+ <% host, pid, queues = worker.to_s.split(':') %>
21
+ <td><%= host %></td>
22
+ <td><%= pid %></td>
23
+ <td><span class="time"><%= worker.started %></span></td>
24
+ <td class='queues'><%= queues.split(',').map { |q| '<a class="queue-tag" href="' + u("/queues/#{q}") + '">' + q + '</a>'}.join('') %></td>
25
+ <td><%= worker.processed %></td>
26
+ <td><%= worker.failed %></td>
27
+ <td class='process'>
28
+ <% data = worker.processing || {} %>
29
+ <% if data['queue'] %>
30
+ <code><%= data['payload']['class'] %></code>
31
+ <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= data['run_at'] %></a></small>
32
+ <% else %>
33
+ <span class='waiting'>Waiting for a job...</span>
34
+ <% end %>
35
+ </td>
36
+ </tr>
37
+ </table>
38
+
39
+ <% elsif params[:id] && !worker_hosts.keys.include?(params[:id]) && params[:id] != 'all' %>
40
+
41
+ <h1>Worker doesn't exist</h1>
42
+
43
+ <% elsif worker_hosts.size == 1 || params[:id] %>
44
+
45
+ <% if worker_hosts.size == 1 || params[:id] == 'all' %>
46
+ <% workers = ResqueSqs.workers %>
47
+ <% else %>
48
+ <% workers = worker_hosts[params[:id]].map { |id| ResqueSqs::Worker.find(id) } %>
49
+ <% end %>
50
+
51
+ <h1 class='wi'><%= workers.size %> Workers</h1>
52
+ <p class='intro'>The workers listed below are all registered as active on your system.</p>
53
+ <table class='workers'>
54
+ <tr>
55
+ <th>&nbsp;</th>
56
+ <th>Where</th>
57
+ <th>Queues</th>
58
+ <th>Processing</th>
59
+ </tr>
60
+ <% for worker in (workers = workers.sort_by { |w| w.to_s }) %>
61
+ <tr class="<%=state = worker.state%>">
62
+ <td class='icon'><img src="<%=u state %>.png" alt="<%= state %>" title="<%= state %>"></td>
63
+
64
+ <% host, pid, queues = worker.to_s.split(':') %>
65
+ <td class='where'><a href="<%=u "workers/#{worker}"%>"><%= host %>:<%= pid %></a></td>
66
+ <td class='queues'><%= queues.split(',').map { |q| '<a class="queue-tag" href="' + u("/queues/#{q}") + '">' + q + '</a>'}.join('') %></td>
67
+
68
+ <td class='process'>
69
+ <% data = worker.processing || {} %>
70
+ <% if data['queue'] %>
71
+ <code><%= data['payload']['class'] %></code>
72
+ <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= data['run_at'] %></a></small>
73
+ <% else %>
74
+ <span class='waiting'>Waiting for a job...</span>
75
+ <% end %>
76
+ </td>
77
+ </tr>
78
+ <% end %>
79
+ <% if workers.empty? %>
80
+ <tr>
81
+ <td colspan='4' class='no-data'>There are no registered workers</td>
82
+ </tr>
83
+ <% end %>
84
+ </table>
85
+ <%=poll%>
86
+
87
+ <% else %>
88
+ <% @subtabs = [] %>
89
+ <h1 class='wi'>Workers</h1>
90
+ <p class='intro'>The hostnames below all have registered workers. Select a hostname to view its workers, or "all" to see all workers.</p>
91
+ <table class='queues'>
92
+ <tr>
93
+ <th>Hostname</th>
94
+ <th>Workers</th>
95
+ </tr>
96
+ <% for hostname, workers in worker_hosts.sort_by { |h,w| h } %>
97
+ <tr>
98
+ <td class='queue'><a class="queue" href="<%= u "workers/#{hostname}" %>"><%= hostname %></a></td>
99
+ <td class='size'><%= workers.size %></td>
100
+ </tr>
101
+ <% end %>
102
+ <tr class="failed">
103
+ <td class='queue failed'><a class="queue" href="<%= u "workers/all" %>">all workers</a></td>
104
+ <td class='size'><%= ResqueSqs.workers.size %></td>
105
+ </tr>
106
+ </table>
107
+
108
+
109
+ <% end %>
@@ -0,0 +1,72 @@
1
+ <% if params[:id] && (worker = ResqueSqs::Worker.find(params[:id])) && worker.job %>
2
+ <h1><%= worker %>'s job</h1>
3
+
4
+ <table>
5
+ <tr>
6
+ <th>&nbsp;</th>
7
+ <th>Where</th>
8
+ <th>Queue</th>
9
+ <th>Started</th>
10
+ <th>Class</th>
11
+ <th>Args</th>
12
+ </tr>
13
+ <tr>
14
+ <td><img src="<%=u 'working.png' %>" alt="working" title="working"></td>
15
+ <% host, pid, _ = worker.to_s.split(':') %>
16
+ <td><a href="<%=u "/workers/#{worker}" %>"><%= host %>:<%= pid %></a></td>
17
+ <% data = worker.job %>
18
+ <% queue = data['queue'] %>
19
+ <td><a class="queue" href="<%=u "/queues/#{queue}" %>"><%= queue %></a></td>
20
+ <td><span class="time"><%= data['run_at'] %></span></td>
21
+ <td>
22
+ <code><%= data['payload']['class'] %></code>
23
+ </td>
24
+ <td><%=h data['payload']['args'].inspect %></td>
25
+ </tr>
26
+ </table>
27
+
28
+ <% else %>
29
+
30
+ <%
31
+ workers = resque.working
32
+ jobs = workers.collect {|w| w.job }
33
+ worker_jobs = workers.zip(jobs)
34
+ worker_jobs = worker_jobs.reject { |w, j| w.idle? }
35
+ %>
36
+
37
+ <h1 class='wi'><%= worker_jobs.size %> of <%= resque.workers.size %> Workers Working</h1>
38
+ <p class='intro'>The list below contains all workers which are currently running a job.</p>
39
+ <table class='workers'>
40
+ <tr>
41
+ <th>&nbsp;</th>
42
+ <th>Where</th>
43
+ <th>Queue</th>
44
+ <th>Processing</th>
45
+ </tr>
46
+ <% if worker_jobs.empty? %>
47
+ <tr>
48
+ <td colspan="4" class='no-data'>Nothing is happening right now...</td>
49
+ </tr>
50
+ <% end %>
51
+
52
+ <% worker_jobs.sort_by {|w, j| j['run_at'] ? j['run_at'] : '' }.each do |worker, job| %>
53
+ <tr>
54
+ <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
55
+ <% host, pid, queues = worker.to_s.split(':') %>
56
+ <td class='where'><a href="<%=u "/workers/#{worker}" %>"><%= host %>:<%= pid %></a></td>
57
+ <td class='queues queue'>
58
+ <a class="queue-tag" href="<%=u "/queues/#{job['queue']}" %>"><%= job['queue'] %></a>
59
+ </td>
60
+ <td class='process'>
61
+ <% if job['queue'] %>
62
+ <code><%= job['payload']['class'] %></code>
63
+ <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= job['run_at'] %></a></small>
64
+ <% else %>
65
+ <span class='waiting'>Waiting for a job...</span>
66
+ <% end %>
67
+ </td>
68
+ </tr>
69
+ <% end %>
70
+ </table>
71
+
72
+ <% end %>
@@ -0,0 +1,271 @@
1
+ require 'sinatra/base'
2
+ require 'erb'
3
+ require 'resque_sqs'
4
+ require 'resque_sqs/version'
5
+ require 'time'
6
+ require 'yaml'
7
+
8
+ if defined? Encoding
9
+ Encoding.default_external = Encoding::UTF_8
10
+ end
11
+
12
+ module ResqueSqs
13
+ class Server < Sinatra::Base
14
+ require 'resque_sqs/server/helpers'
15
+
16
+ dir = File.dirname(File.expand_path(__FILE__))
17
+
18
+ set :views, "#{dir}/server/views"
19
+
20
+ if respond_to? :public_folder
21
+ set :public_folder, "#{dir}/server/public"
22
+ else
23
+ set :public, "#{dir}/server/public"
24
+ end
25
+
26
+ set :static, true
27
+
28
+ helpers do
29
+ include Rack::Utils
30
+ alias_method :h, :escape_html
31
+
32
+ def current_section
33
+ url_path request.path_info.sub('/','').split('/')[0].downcase
34
+ end
35
+
36
+ def current_page
37
+ url_path request.path_info.sub('/','')
38
+ end
39
+
40
+ def url_path(*path_parts)
41
+ [ path_prefix, path_parts ].join("/").squeeze('/')
42
+ end
43
+ alias_method :u, :url_path
44
+
45
+ def path_prefix
46
+ request.env['SCRIPT_NAME']
47
+ end
48
+
49
+ def class_if_current(path = '')
50
+ 'class="current"' if current_page[0, path.size] == path
51
+ end
52
+
53
+ def tab(name)
54
+ dname = name.to_s.downcase
55
+ path = url_path(dname)
56
+ "<li #{class_if_current(path)}><a href='#{path}'>#{name}</a></li>"
57
+ end
58
+
59
+ def tabs
60
+ ResqueSqs::Server.tabs
61
+ end
62
+
63
+ def redis_get_size(key)
64
+ case ResqueSqs.redis.type(key)
65
+ when 'none'
66
+ []
67
+ when 'list'
68
+ ResqueSqs.redis.llen(key)
69
+ when 'set'
70
+ ResqueSqs.redis.scard(key)
71
+ when 'string'
72
+ ResqueSqs.redis.get(key).length
73
+ when 'zset'
74
+ ResqueSqs.redis.zcard(key)
75
+ end
76
+ end
77
+
78
+ def redis_get_value_as_array(key, start=0)
79
+ case ResqueSqs.redis.type(key)
80
+ when 'none'
81
+ []
82
+ when 'list'
83
+ ResqueSqs.redis.lrange(key, start, start + 20)
84
+ when 'set'
85
+ ResqueSqs.redis.smembers(key)[start..(start + 20)]
86
+ when 'string'
87
+ [ResqueSqs.redis.get(key)]
88
+ when 'zset'
89
+ ResqueSqs.redis.zrange(key, start, start + 20)
90
+ end
91
+ end
92
+
93
+ def show_args(args)
94
+ Array(args).map do |a|
95
+ a.to_yaml
96
+ end.join("\n")
97
+ end
98
+
99
+ def worker_hosts
100
+ @worker_hosts ||= worker_hosts!
101
+ end
102
+
103
+ def worker_hosts!
104
+ hosts = Hash.new { [] }
105
+
106
+ ResqueSqs.workers.each do |worker|
107
+ host, _ = worker.to_s.split(':')
108
+ hosts[host] += [worker.to_s]
109
+ end
110
+
111
+ hosts
112
+ end
113
+
114
+ def partial?
115
+ @partial
116
+ end
117
+
118
+ def partial(template, local_vars = {})
119
+ @partial = true
120
+ erb(template.to_sym, {:layout => false}, local_vars)
121
+ ensure
122
+ @partial = false
123
+ end
124
+
125
+ def poll
126
+ if @polling
127
+ text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
128
+ else
129
+ text = "<a href='#{u(request.path_info)}.poll' rel='poll'>Live Poll</a>"
130
+ end
131
+ "<p class='poll'>#{text}</p>"
132
+ end
133
+
134
+ end
135
+
136
+ def show(page, layout = true)
137
+ response["Cache-Control"] = "max-age=0, private, must-revalidate"
138
+ begin
139
+ erb page.to_sym, {:layout => layout}, :resque => ResqueSqs
140
+ rescue Errno::ECONNREFUSED
141
+ erb :error, {:layout => false}, :error => "Can't connect to Redis! (#{ResqueSqs.redis_id})"
142
+ end
143
+ end
144
+
145
+ def show_for_polling(page)
146
+ content_type "text/html"
147
+ @polling = true
148
+ show(page.to_sym, false).gsub(/\s{1,}/, ' ')
149
+ end
150
+
151
+ # to make things easier on ourselves
152
+ get "/?" do
153
+ redirect url_path(:overview)
154
+ end
155
+
156
+ %w( overview workers ).each do |page|
157
+ get "/#{page}.poll/?" do
158
+ show_for_polling(page)
159
+ end
160
+
161
+ get "/#{page}/:id.poll/?" do
162
+ show_for_polling(page)
163
+ end
164
+ end
165
+
166
+ %w( overview queues working workers key ).each do |page|
167
+ get "/#{page}/?" do
168
+ show page
169
+ end
170
+
171
+ get "/#{page}/:id/?" do
172
+ show page
173
+ end
174
+ end
175
+
176
+ post "/queues/:id/remove" do
177
+ ResqueSqs.remove_queue(params[:id])
178
+ redirect u('queues')
179
+ end
180
+
181
+ get "/failed/?" do
182
+ if ResqueSqs::Failure.url
183
+ redirect ResqueSqs::Failure.url
184
+ else
185
+ show :failed
186
+ end
187
+ end
188
+
189
+ get "/failed/:queue" do
190
+ if ResqueSqs::Failure.url
191
+ redirect ResqueSqs::Failure.url
192
+ else
193
+ show :failed
194
+ end
195
+ end
196
+
197
+ post "/failed/clear" do
198
+ ResqueSqs::Failure.clear
199
+ redirect u('failed')
200
+ end
201
+
202
+ post "/failed/:queue/clear" do
203
+ ResqueSqs::Failure.clear params[:queue]
204
+ redirect u('failed')
205
+ end
206
+
207
+ post "/failed/requeue/all" do
208
+ ResqueSqs::Failure.count.times do |num|
209
+ ResqueSqs::Failure.requeue(num)
210
+ end
211
+ redirect u('failed')
212
+ end
213
+
214
+ post "/failed/:queue/requeue/all" do
215
+ ResqueSqs::Failure.requeue_queue ResqueSqs::Failure.job_queue_name(params[:queue])
216
+ redirect url_path("/failed/#{params[:queue]}")
217
+ end
218
+
219
+ get "/failed/requeue/:index/?" do
220
+ ResqueSqs::Failure.requeue(params[:index])
221
+ if request.xhr?
222
+ return ResqueSqs::Failure.all(params[:index])['retried_at']
223
+ else
224
+ redirect u('failed')
225
+ end
226
+ end
227
+
228
+ get "/failed/remove/:index/?" do
229
+ ResqueSqs::Failure.remove(params[:index])
230
+ redirect u('failed')
231
+ end
232
+
233
+ get "/stats/?" do
234
+ redirect url_path("/stats/resque")
235
+ end
236
+
237
+ get "/stats/:id/?" do
238
+ show :stats
239
+ end
240
+
241
+ get "/stats/keys/:key/?" do
242
+ show :stats
243
+ end
244
+
245
+ get "/stats.txt/?" do
246
+ info = ResqueSqs.info
247
+
248
+ stats = []
249
+ stats << "resque.pending=#{info[:pending]}"
250
+ stats << "resque.processed+=#{info[:processed]}"
251
+ stats << "resque.failed+=#{info[:failed]}"
252
+ stats << "resque.workers=#{info[:workers]}"
253
+ stats << "resque.working=#{info[:working]}"
254
+
255
+ ResqueSqs.queues.each do |queue|
256
+ stats << "queues.#{queue}=#{ResqueSqs.size(queue)}"
257
+ end
258
+
259
+ content_type 'text/html'
260
+ stats.join "\n"
261
+ end
262
+
263
+ def resque
264
+ ResqueSqs
265
+ end
266
+
267
+ def self.tabs
268
+ @tabs ||= ["Overview", "Working", "Failed", "Queues", "Workers", "Stats"]
269
+ end
270
+ end
271
+ end