resque-cleaner 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,7 +1,11 @@
1
+ ## 0.2.0 (2011-04-06)
2
+
3
+ * Extended with resque-web
4
+
1
5
  ## 0.1.1 (2010-12-30)
2
6
 
3
- * Fix for ruby 1.9.2
4
- * Fix a bug on #retried? method
7
+ * Fixed for ruby 1.9.2
8
+ * Fixed a bug on #retried? method
5
9
 
6
10
  ## 0.1.0 (2010-11-24)
7
11
 
data/README.markdown CHANGED
@@ -8,16 +8,13 @@ Description
8
8
  -----------
9
9
 
10
10
  ResqueCleaner is a [Resque](https://github.com/defunkt/resque) plugin which
11
- helps you to deal with failed jobs on Resque by:
11
+ aims to help you to clean up failed jobs on Resque by:
12
12
 
13
13
  * Showing stats of failed jobs
14
14
  * Retrying failed jobs
15
15
  * Removing failed jobs
16
16
  * Filtering failed jobs
17
17
 
18
- Although ResqueCleaner has not integrated with Resque's web-based interface yet,
19
- it is pretty easy to use on irb(console).
20
-
21
18
 
22
19
  Installation
23
20
  ------------
@@ -27,8 +24,22 @@ Install as a gem:
27
24
  $ gem install resque-cleaner
28
25
 
29
26
 
30
- Usage
31
- -----
27
+ Resque-Web integration
28
+ ----------------------
29
+
30
+ ![Screen 1](https://github.com/ono/resque-cleaner/raw/master/misc/resque-cleaner-main.png)
31
+ ![Screen 2](https://github.com/ono/resque-cleaner/raw/master/misc/resque-cleaner-list.png)
32
+
33
+ You have to load ResqueCleaner to enable the Cleaner tab.
34
+
35
+ require 'resque-cleaner'
36
+
37
+ Console
38
+ -------
39
+
40
+ Hopefully a situation of your failed jobs is simple enough to get figured out through
41
+ the web interface. But, if not, a powerful filtering feature of ResqueCleaner may help
42
+ you to understand what is going on with your console(irb).
32
43
 
33
44
  **Create Instance**
34
45
 
@@ -234,11 +245,4 @@ application; it should be quick even if there are huge number of failed jobs.
234
245
  > cleaner.limiter.on?
235
246
  => false
236
247
 
237
- TODO
238
- ----
239
-
240
- * Integration with Resque's sinatra based front end.
241
- * More stats.
242
-
243
- Any suggestion or idea are welcomed.
244
248
 
@@ -0,0 +1,61 @@
1
+
2
+ #main .cleaner .title h1 { float: left }
3
+
4
+ #main .cleaner .sub_header {color: #888; font-size: 80%; font-weight: bold}
5
+
6
+ #main .cleaner .control_panel {
7
+ margin: 5px 0 10px; padding: 5px; background: #eee; display: inline-block;
8
+ -webkit-border-radius:5px; border:1px solid #ccc;
9
+ }
10
+
11
+ #main .cleaner #exec { color: black; }
12
+ #main .cleaner #exec select { margin-right: 20px }
13
+ #main .cleaner #exec a { margin-right: 5px}
14
+ #main .cleaner #exec a.disabled { color: #aaa}
15
+
16
+ #main .cleaner table.class_list { width: auto }
17
+ #main .cleaner td.number { text-align: right }
18
+ #main .cleaner tr.total { border-top: 3px double #ccc}
19
+
20
+ #main .cleaner form { float: none; margin: 0}
21
+
22
+ #main .cleaner .warning { margin: 30px 0; padding: 10px; background: #fdd; display: inline-block; }
23
+
24
+ #main .clearfix:after {
25
+ content: ".";
26
+ display: block;
27
+ height: 0;
28
+ clear: both;
29
+ visibility: hidden;
30
+ }
31
+ #main .cleaner ul.failed {
32
+ margin-bottom: 10px
33
+ }
34
+
35
+ #main .cleaner .list_info{
36
+ color: #999; text-align: center;
37
+ }
38
+ #main .cleaner .list_info a{
39
+ color: #666
40
+ }
41
+ #main .cleaner .list_info .list_summary{
42
+ vertical-align: baseline;
43
+ display: inline-block;
44
+ margin: 0; padding:0;
45
+ }
46
+ #main .cleaner ul.pagination {
47
+ display: inline-block;
48
+ vertical-align: baseline;
49
+ margin:0; padding:0;
50
+ }
51
+ #main .cleaner ul.pagination li {
52
+ list-style:none; float: left; padding: 0 3px;
53
+ }
54
+ #main .cleaner ul.pagination li.current {
55
+ color: #333; font-weight: bold;
56
+ }
57
+ #main .cleaner ul.pagination li.summary{
58
+ padding-right: 10px
59
+ }
60
+
61
+
@@ -0,0 +1,13 @@
1
+ <div class="warning">
2
+ <p>
3
+ There are more than <%= @cleaner.limiter.maximum%> jobs. ResqueCleaner handles only recent <%= @cleaner.limiter.maximum %> jobs. See the Limiter section on <a href="https://github.com/ono/resque-cleaner" target="_blank">README</a> for more detail.
4
+ </p>
5
+ <p>
6
+ <form method="post" action="cleaner_stale">
7
+ <input type="hidden" name="action" value="clear_stale" />
8
+ <input type="submit" onclick="return confirm('Are you sure?')" value="Clear all jobs older than <%= @cleaner.limiter.count %>th job."/>
9
+ (<%= @cleaner.failure.count - @cleaner.limiter.maximum %> jobs will be cleared)
10
+ </form>
11
+ </p>
12
+ </div>
13
+
@@ -0,0 +1,50 @@
1
+ <div class="list_info clearfix">
2
+
3
+ <ul class="pagination">
4
+ <li class="summary">
5
+ <%= @paginate.first_index%> - <%= @paginate.last_index%> / <%= @paginate.total_size%>
6
+ </li>
7
+ <% if @paginate.max_page>1 %>
8
+ <% if @paginate.first_page? %>
9
+ <li class="prev off">&lt;&lt;newer</li>
10
+ <% else %>
11
+ <li class="prev"><a href="<%= @paginate.page_url(:prev)%>">&lt;&lt;newer</a></li>
12
+ <% end %>
13
+
14
+ <% 1.upto(6<@paginate.max_page ? 6 : @paginate.max_page) do |pg| %>
15
+ <% if @paginate.page==pg %>
16
+ <li class="current"><%=pg%></li>
17
+ <% else %>
18
+ <li><a href="<%= @paginate.page_url(pg)%>"><%=pg%></a></li>
19
+ <% end %>
20
+ <% end %>
21
+
22
+ <% if @paginate.max_page > 6 %>
23
+ <% if @paginate.max_page!=@paginate.page %>
24
+ <% if @paginate.page>7 %>
25
+ <li class="off">...</li>
26
+ <% end %>
27
+ <% if @paginate.page>6 %>
28
+ <li class="current"><%=@paginate.page%></li>
29
+ <% end %>
30
+ <% end %>
31
+ <% if @paginate.max_page>7 && @paginate.page+1!=@paginate.max_page %>
32
+ <li class="off">...</li>
33
+ <% end %>
34
+
35
+ <% if @paginate.max_page==@paginate.page %>
36
+ <li class="current"><%=@paginate.max_page%></li>
37
+ <% else %>
38
+ <li><a href="<%= @paginate.page_url(@paginate.max_page)%>"><%=@paginate.max_page%></a></li>
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <% if @paginate.last_page? %>
43
+ <li class="next off">older&gt;&gt;</li>
44
+ <% else %>
45
+ <li class="next"><a href="<%= @paginate.page_url(:next)%>">older&gt;&gt;</a></li>
46
+ <% end %>
47
+ <% end %>
48
+ </ul>
49
+ </div>
50
+
@@ -0,0 +1,43 @@
1
+ <link href="/cleaner/public/cleaner.css" media="screen" rel="stylesheet" type="text/css">
2
+
3
+ <div class="cleaner">
4
+ <div class="title clearfix">
5
+ <h1>Job Classes Failed</h1>
6
+ </div>
7
+
8
+ <table class="class_list">
9
+ <tr>
10
+ <th>Class</th>
11
+ <th>Failed</th>
12
+ <th>In last 1 hour</th>
13
+ <th>In last 3 hours</th>
14
+ <th>In last 24 hours</th>
15
+ <th>In last 3 days</th>
16
+ <th>In last 7 days</th>
17
+ </tr>
18
+ <% @stats.each do |klass,count| %>
19
+ <tr>
20
+ <td><%= klass %></td>
21
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>"><%= count["total"] %></a></td>
22
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>&f=1"><%= count["1h"] %></a></td>
23
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>&f=3"><%= count["3h"] %></a></td>
24
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>&f=24"><%= count["1d"] %></a></td>
25
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>&f=72"><%= count["3d"] %></a></td>
26
+ <td class="number"><a href="/cleaner_list?c=<%=klass%>&f=168"><%= count["7d"] %></a></td>
27
+ </tr>
28
+ <% end %>
29
+ <tr class="total">
30
+ <td>Total</td>
31
+ <td class="number"><a href="/cleaner_list"><%= @total["total"] %></a></td>
32
+ <td class="number"><a href="/cleaner_list?f=1"><%= @total["1h"] %></a></td>
33
+ <td class="number"><a href="/cleaner_list?f=3"><%= @total["3h"] %></a></td>
34
+ <td class="number"><a href="/cleaner_list?f=24"><%= @total["1d"] %></a></td>
35
+ <td class="number"><a href="/cleaner_list?f=72"><%= @total["3d"] %></a></td>
36
+ <td class="number"><a href="/cleaner_list?f=168"><%= @total["7d"] %></a></td>
37
+ </tr>
38
+ </table>
39
+
40
+ <% if @cleaner.limiter.on? %>
41
+ <%= erb File.read(ResqueCleaner::Server.erb_path("_limiter.erb")) %>
42
+ <% end %>
43
+ </div>
@@ -0,0 +1,8 @@
1
+ <link href="/cleaner/public/cleaner.css" media="screen" rel="stylesheet" type="text/css">
2
+
3
+ <div class="cleaner">
4
+ <p class="message"><%= @msg %></p>
5
+ <p class="back_to_list">
6
+ <a href="<%=@url%>">Back to List</a>
7
+ </p>
8
+ </div>
@@ -0,0 +1,169 @@
1
+ <link href="/cleaner/public/cleaner.css" media="screen" rel="stylesheet" type="text/css">
2
+
3
+ <!-- Many code was copied from failed.erb of the original resque -->
4
+ <div class="cleaner">
5
+ <div class="title clearfix">
6
+ <h1>Failed Jobs</h1>
7
+ </div>
8
+
9
+ <div class="clearfix">
10
+ <div class="control_panel sub_header">
11
+ <form method="get">
12
+ <span class="class_filter">
13
+ Class: <%= class_filter("filter_class","c",@klasses,@klass)%>
14
+ </span>
15
+ <span class="time_filter">
16
+ From: <%= time_filter("filter_from","f",@from)%>
17
+ </span>
18
+ <span class="time_filter">
19
+ To: <%= time_filter("filter_to","t",@to)%>
20
+ </span>
21
+ <input type="submit" value="Filter" />
22
+ </form>
23
+ </div>
24
+ </div>
25
+
26
+ <% if @count > 0 %>
27
+ <div class="clearfix">
28
+ <div class="control_panel sub_header">
29
+ <form method="post" id="exec" action="/cleaner_exec">
30
+ <input type="hidden" name="c" value="<%=@klass%>" />
31
+ <input type="hidden" name="f" value="<%=@from%>" />
32
+ <input type="hidden" name="t" value="<%=@to%>" />
33
+ <input type="hidden" name="p" value="<%=@paginate.page%>" />
34
+ <select id="form_action" name="action">
35
+ <option id="default_option" value="" selected="selected">-- Select Action --</option>
36
+ <option value="clear">Clear</option>
37
+ <option value="retry_and_clear">Retry and Clear</option>
38
+ <option value="retry">Retry</option>
39
+ </select>
40
+ <a href="#" id="select_all">select all</a>
41
+ <a href="#" id="reset_all">reset</a>
42
+
43
+ <% if @paginate.max_page > 1 %>
44
+ <input type="checkbox" name="select_all_pages" value="1" id="select_all_pages" />Select all <%=@count%> jobs
45
+ <% end %>
46
+ <input type="hidden" name="sha1" id="sha1_list" />
47
+
48
+ </form>
49
+ </div>
50
+ </div>
51
+ <% end %>
52
+
53
+ <% start = 0 %>
54
+ <% failed = @paginate.paginated_jobs%>
55
+ <% index = 0 %>
56
+
57
+ <% if @paginate.max_page > 0 %>
58
+ <%= erb File.read(ResqueCleaner::Server.erb_path("_paginate.erb")) %>
59
+ <ul class='failed'>
60
+ <%for job in failed%>
61
+ <% index += 1 %>
62
+ <li>
63
+ <dl>
64
+ <% if job.nil? %>
65
+ <dt>Error</dt>
66
+ <dd>Job <%= index%> could not be parsed; perhaps it contains invalid JSON?</dd>
67
+ <% else %>
68
+ <dt>
69
+ <input type="checkbox" id="<%=Digest::SHA1.hexdigest job.to_json %>" />
70
+ </dt>
71
+ <dd>&nbsp;</dd>
72
+ <dt>Worker</dt>
73
+ <dd>
74
+ <a href="<%= u(:workers, job['worker']) %>"><%= job['worker'].split(':')[0...2].join(':') %></a> on <b class='queue-tag'><%= job['queue'] %></b > at <b><span class="time"><%= job['failed_at'] %></span></b>
75
+ <% if job['retried_at'] %>
76
+ <div class='retried'>
77
+ Retried <b><span class="time"><%= job['retried_at'] %></span></b>
78
+ </div>
79
+ <% end %>
80
+ </dd>
81
+ <dt>Class</dt>
82
+ <dd><code><%= job['payload'] ? job['payload']['class'] : 'nil' %></code></dd>
83
+ <dt>Arguments</dt>
84
+ <dd><pre><%=h job['payload'] ? show_args(job['payload']['args']) : 'nil' %></pre></dd>
85
+ <dt>Exception</dt>
86
+ <dd><code><%= job['exception'] %></code></dd>
87
+ <dt>Error</dt>
88
+ <dd class='error'>
89
+ <% if job['backtrace'] %>
90
+ <a href="#" class="backtrace"><%= h(job['error']) %></a>
91
+ <pre style='display:none'><%=h job['backtrace'].join("\n") %></pre>
92
+ <% else %>
93
+ <%=h job['error'] %>
94
+ <% end %>
95
+ </dd>
96
+ <% end %>
97
+ </dl>
98
+ <div class='r'>
99
+ </div>
100
+ </li>
101
+ <%end%>
102
+ </ul>
103
+ <%= erb File.read(ResqueCleaner::Server.erb_path("_paginate.erb")) %>
104
+ <% else %>
105
+ Clean!
106
+ <% end %>
107
+ </div>
108
+
109
+ <script>
110
+ $(document).ready(function(){
111
+ $('#select_all_pages').click(function() {
112
+ updateCheckboxStaus();
113
+ });
114
+
115
+ $('#select_all').click(function() {
116
+ if (!$(this).hasClass('disabled')) {
117
+ $('.failed input').attr('checked','checked');
118
+ }
119
+ return false;
120
+ });
121
+ $('#reset_all').click(function() {
122
+ if (!$(this).hasClass('disabled')) {
123
+ $('.failed input').removeAttr('checked');
124
+ }
125
+ return false;
126
+ });
127
+
128
+ $('#form_action').change( function() {
129
+ if ($('#form_action option:selected').val()=='') return;
130
+
131
+ if ($('#select_all_pages:checked, .failed input:checked').length==0) {
132
+ alert('Please select jobs.');
133
+ $('#default_option').attr('selected','selected');
134
+ return false;
135
+ }
136
+
137
+ if (!confirm('Do you really want to proceed?')) {
138
+ $('#default_option').attr('selected','selected');
139
+ return false;
140
+ }
141
+
142
+ if ($('#select_all_pages:checked').length==0) {
143
+ setSha1();
144
+ }
145
+ $('#exec').submit();
146
+ });
147
+ });
148
+
149
+ function setSha1() {
150
+ var sha1 = "";
151
+ $('.failed input:checked').each( function() {
152
+ if (sha1.length>0) sha1 += ",";
153
+ sha1 += $(this).attr("id");
154
+ });
155
+
156
+ $('#sha1_list').val(sha1);
157
+ }
158
+
159
+ function updateCheckboxStaus() {
160
+ if ($('#select_all_pages:checked').length==1) {
161
+ $('#exec a').addClass('disabled');
162
+ $('.failed input').attr('disabled','disabled');
163
+ } else {
164
+ $('#exec a').removeClass('disabled');
165
+ $('.failed input').removeAttr('disabled');
166
+ }
167
+ };
168
+
169
+ </script>
@@ -0,0 +1,205 @@
1
+ # Extends Resque Web Based UI.
2
+ # Structure has been borrowed from ResqueScheduler.
3
+ module ResqueCleaner
4
+ module Server
5
+
6
+ begin
7
+ require 'yajl/json_gem'
8
+ rescue Exception
9
+ require 'json'
10
+ end
11
+
12
+ def self.erb_path(filename)
13
+ File.join(File.dirname(__FILE__), 'server', 'views', filename)
14
+ end
15
+ def self.public_path(filename)
16
+ File.join(File.dirname(__FILE__), 'server', 'public', filename)
17
+ end
18
+
19
+ # Pagination helpr for list page.
20
+ class Paginate
21
+ attr_accessor :page_size, :page, :jobs, :url
22
+ def initialize(jobs, url, page=1, page_size=20)
23
+ @jobs = jobs
24
+ @url = url
25
+ @page = (!page || page < 1) ? 1 : page
26
+ @page_size = 20
27
+ end
28
+
29
+ def first_index
30
+ @page_size * (@page-1)
31
+ end
32
+
33
+ def last_index
34
+ last = first_index + @page_size - 1
35
+ last > @jobs.size-1 ? @jobs.size-1 : last
36
+ end
37
+
38
+ def paginated_jobs
39
+ @jobs[first_index,@page_size]
40
+ end
41
+
42
+ def first_page?
43
+ @page <= 1
44
+ end
45
+
46
+ def last_page?
47
+ @page >= max_page
48
+ end
49
+
50
+ def page_url(page)
51
+ u = @url
52
+ u += @url.include?("?") ? "&" : "?"
53
+ if page.is_a?(Symbol)
54
+ page = @page - 1 if page==:prev
55
+ page = @page + 1 if page==:next
56
+ end
57
+ u += "p=#{page}"
58
+ end
59
+
60
+ def total_size
61
+ @jobs.size
62
+ end
63
+
64
+ def max_page
65
+ ((total_size-1) / @page_size) + 1
66
+ end
67
+ end
68
+
69
+ def self.included(base)
70
+ require 'digest/sha1'
71
+ base.class_eval do
72
+ helpers do
73
+ def time_filter(id, name, value)
74
+ html = "<select id=\"#{id}\" name=\"#{name}\">"
75
+ html += "<option value=\"\">-</option>"
76
+ [1, 3, 6, 12, 24].each do |h|
77
+ selected = h.to_s == value ? 'selected="selected"' : ''
78
+ html += "<option #{selected} value=\"#{h}\">#{h} #{h==1 ? "hour" : "hours"} ago</option>"
79
+ end
80
+ [3, 7, 14, 28].each do |d|
81
+ selected = (d*24).to_s == value ? 'selected="selected"' : ''
82
+ html += "<option #{selected} value=\"#{d*24}\">#{d} days ago</option>"
83
+ end
84
+ html += "</select>"
85
+ end
86
+
87
+ def class_filter(id, name, klasses, value)
88
+ html = "<select id=\"#{id}\" name=\"#{name}\">"
89
+ html += "<option value=\"\">-</option>"
90
+ klasses.each do |k|
91
+ selected = k == value ? 'selected="selected"' : ''
92
+ html += "<option #{selected} value=\"#{k}\">#{k}</option>"
93
+ end
94
+ html += "</select>"
95
+ end
96
+ end
97
+
98
+ get "/cleaner" do
99
+ load_cleaner_filter
100
+
101
+ @jobs = cleaner.select
102
+ @stats, @total = {}, {"total" => 0, "1h" => 0, "3h" => 0, "1d" => 0, "3d" => 0, "7d" => 0}
103
+ @jobs.each do |job|
104
+ klass = job["payload"]["class"]
105
+ failed_at = Time.parse job["failed_at"]
106
+
107
+ @stats[klass] ||= {"total" => 0, "1h" => 0, "3h" => 0, "1d" => 0, "3d" => 0, "7d" => 0}
108
+ items = [@stats[klass],@total]
109
+
110
+ items.each{|a| a["total"] += 1}
111
+ items.each{|a| a["1h"] += 1} if failed_at >= hours_ago(1)
112
+ items.each{|a| a["3h"] += 1} if failed_at >= hours_ago(3)
113
+ items.each{|a| a["1d"] += 1} if failed_at >= hours_ago(24)
114
+ items.each{|a| a["3d"] += 1} if failed_at >= hours_ago(24*3)
115
+ items.each{|a| a["7d"] += 1} if failed_at >= hours_ago(24*7)
116
+ end
117
+
118
+ erb File.read(ResqueCleaner::Server.erb_path('cleaner.erb'))
119
+ end
120
+
121
+ get "/cleaner_list" do
122
+ load_cleaner_filter
123
+
124
+ block = lambda{|j|
125
+ (!@from || j.after?(hours_ago(@from))) &&
126
+ (!@to || j.before?(hours_ago(@to))) &&
127
+ (!@klass || j.klass?(@klass))
128
+ }
129
+
130
+ @failed = cleaner.select(&block).reverse
131
+
132
+ url = "cleaner_list?c=#{@klass}&f=#{@from}&t=#{@to}"
133
+ @paginate = Paginate.new(@failed, url, params[:p].to_i)
134
+
135
+ @klasses = cleaner.stats_by_class.keys
136
+ @count = cleaner.select(&block).size
137
+
138
+ erb File.read(ResqueCleaner::Server.erb_path('cleaner_list.erb'))
139
+ end
140
+
141
+ post "/cleaner_exec" do
142
+ load_cleaner_filter
143
+
144
+ @sha1 = nil
145
+ if params[:select_all_pages]!="1"
146
+ @sha1 = {}
147
+ params[:sha1].split(",").each do |s|
148
+ @sha1[s] = true
149
+ end
150
+ end
151
+
152
+ block = lambda{|j|
153
+ (!@from || j.after?(hours_ago(@from))) &&
154
+ (!@to || j.before?(hours_ago(@to))) &&
155
+ (!@klass || j.klass?(@klass))
156
+ (!@sha1 || @sha1[Digest::SHA1.hexdigest(j.to_json)])
157
+ }
158
+
159
+ count =
160
+ case params[:action]
161
+ when "clear" then cleaner.clear(&block)
162
+ when "retry_and_clear" then cleaner.requeue(true,&block)
163
+ when "retry" then cleaner.requeue(false,{},&block)
164
+ end
165
+
166
+ @msg = "processed #{count} jobs."
167
+ @url = "cleaner_list?c=#{@klass}&f=#{@from}&t=#{@to}"
168
+ erb File.read(ResqueCleaner::Server.erb_path('cleaner_exec.erb'))
169
+ end
170
+
171
+ post "/cleaner_stale" do
172
+ cleaner.clear_stale
173
+ redirect "/cleaner"
174
+ end
175
+
176
+ get /cleaner\/public\/([a-z]+\.[a-z]+)/ do
177
+ send_file ResqueCleaner::Server.public_path(params[:captures].first)
178
+ end
179
+ end
180
+
181
+ end
182
+
183
+ def cleaner
184
+ @cleaner ||= Resque::Plugins::ResqueCleaner.new
185
+ @cleaner.print_message = false
186
+ @cleaner
187
+ end
188
+
189
+ def load_cleaner_filter
190
+ @from = params[:f]=="" ? nil : params[:f]
191
+ @to = params[:t]=="" ? nil : params[:t]
192
+ @klass = params[:c]=="" ? nil : params[:c]
193
+ end
194
+
195
+ def hours_ago(h)
196
+ Time.now - h.to_i*60*60
197
+ end
198
+ Resque::Server.tabs << 'Cleaner'
199
+ end
200
+ end
201
+
202
+ Resque::Server.class_eval do
203
+ include ResqueCleaner::Server
204
+ end
205
+
@@ -1,4 +1,7 @@
1
1
  require 'time'
2
+ require 'resque'
3
+ require 'resque/server'
4
+
2
5
  module Resque
3
6
  module Plugins
4
7
  # ResqueCleaner class provides useful functionalities to retry or clean
@@ -258,5 +261,5 @@ module Resque
258
261
  end
259
262
  end
260
263
 
261
-
264
+ require 'resque_cleaner/server'
262
265
 
@@ -1,19 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
2
  require 'time'
3
3
  context "ResqueCleaner" do
4
- def create_and_process_jobs(queue,worker,num,date,job,*args)
5
- Timecop.freeze(date) do
6
- num.times do
7
- Resque::Job.create(queue, job, *args)
8
- end
9
- worker.work(0)
10
- end
11
- end
12
-
13
- def queue_size(*queues)
14
- queues.inject(0){|sum,queue| sum + Resque.size(queue).to_i}
15
- end
16
-
17
4
  setup do
18
5
  Resque.redis.flushall
19
6
 
@@ -0,0 +1,44 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper')
2
+
3
+ # Pull in the server test_helper from resque
4
+ require 'resque/server/test_helper.rb'
5
+
6
+ def setup_some_failed_jobs
7
+ Resque.redis.flushall
8
+
9
+ @worker = Resque::Worker.new(:jobs,:jobs2)
10
+
11
+ 10.times {|i|
12
+ create_and_process_jobs :jobs, @worker, 1, Time.now, BadJob, "test_#{i}"
13
+ }
14
+
15
+ @cleaner = Resque::Plugins::ResqueCleaner.new
16
+ @cleaner.print_message = false
17
+ end
18
+
19
+ context "resque-web" do
20
+ setup do
21
+ setup_some_failed_jobs
22
+ end
23
+
24
+ test "#cleaner should respond with success" do
25
+ get "/cleaner_list"
26
+ assert last_response.ok?, last_response.errors
27
+ end
28
+
29
+ test "#cleaner_list should respond with success" do
30
+ get "/cleaner_list"
31
+ assert last_response.ok?, last_response.errors
32
+ end
33
+
34
+ test '#cleaner_list shows the failed jobs' do
35
+ get "/cleaner_list"
36
+ assert last_response.body.include?('BadJob')
37
+ end
38
+
39
+ test '#cleaner_exec clears job' do
40
+ post "/cleaner_exec", :action => "clear", :sha1 => Digest::SHA1.hexdigest(@cleaner.select[0].to_json)
41
+ assert_equal 9, @cleaner.select.size
42
+ end
43
+ end
44
+
data/test/test_helper.rb CHANGED
@@ -120,3 +120,20 @@ class BadJobWithSyntaxError
120
120
  raise SyntaxError, "Extra Bad job!"
121
121
  end
122
122
  end
123
+
124
+ #
125
+ # helper methods
126
+ #
127
+
128
+ def create_and_process_jobs(queue,worker,num,date,job,*args)
129
+ Timecop.freeze(date) do
130
+ num.times do
131
+ Resque::Job.create(queue, job, *args)
132
+ end
133
+ worker.work(0)
134
+ end
135
+ end
136
+
137
+ def queue_size(*queues)
138
+ queues.inject(0){|sum,queue| sum + Resque.size(queue).to_i}
139
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: resque-cleaner
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 1
9
- - 1
10
- version: 0.1.1
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Tatsuya Ono
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-12-30 00:00:00 +00:00
17
+ date: 2011-04-06 00:00:00 +01:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 15
30
28
  segments:
31
29
  - 1
32
30
  - 0
@@ -49,9 +47,17 @@ files:
49
47
  - Rakefile
50
48
  - LICENSE
51
49
  - lib/resque-cleaner.rb
50
+ - lib/resque_cleaner/server/public/cleaner.css
51
+ - lib/resque_cleaner/server/views/_limiter.erb
52
+ - lib/resque_cleaner/server/views/_paginate.erb
53
+ - lib/resque_cleaner/server/views/cleaner.erb
54
+ - lib/resque_cleaner/server/views/cleaner_exec.erb
55
+ - lib/resque_cleaner/server/views/cleaner_list.erb
56
+ - lib/resque_cleaner/server.rb
52
57
  - lib/resque_cleaner.rb
53
58
  - test/redis-test.conf
54
59
  - test/resque_cleaner_test.rb
60
+ - test/resque_web_test.rb
55
61
  - test/test_helper.rb
56
62
  has_rdoc: true
57
63
  homepage: http://github.com/ono/resque-cleaner
@@ -67,7 +73,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
73
  requirements:
68
74
  - - ">="
69
75
  - !ruby/object:Gem::Version
70
- hash: 3
71
76
  segments:
72
77
  - 0
73
78
  version: "0"
@@ -76,7 +81,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
81
  requirements:
77
82
  - - ">="
78
83
  - !ruby/object:Gem::Version
79
- hash: 3
80
84
  segments:
81
85
  - 0
82
86
  version: "0"