resque_manager 3.3.1 → 3.3.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.
- checksums.yaml +4 -4
- data/app/controllers/resque_manager/resque_controller.rb +248 -245
- data/app/views/resque_manager/resque/status.html.erb +1 -1
- data/app/views/resque_manager/resque/statuses.html.erb +2 -2
- data/config/routes.rb +1 -0
- data/lib/resque_manager/version.rb +1 -1
- data/lib/tasks/worker.rake +50 -1
- data/test/dummy/log/test.log +1249 -0
- data/test/functional/resque_manager/resque_controller_test.rb +30 -17
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 735b88a6f88951d523090c3533a1dcac2e753ae9
|
4
|
+
data.tar.gz: 7647c53321229d8920c64fc7364982afb5e1a80c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20712d2a060222720058f5ca3d8ea02157b0c3aa41a67a1bd9055fffca605d4a368c8501cb0ee6eedd19311687372f234de44439cc7aed84e8c189673985bc23
|
7
|
+
data.tar.gz: ebfb572eaeab14c7ae4b726b628990bf562b6d2f65885f3e83aaedefd1c27e95a20db6ea9c5297ca8063b196e734a1bf65755f5de5807f9b2816a49aeddf4aee
|
@@ -1,313 +1,316 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require '
|
1
|
+
# Only load this file if it's running from the server, not from a rake task starting a worker. Workers don't need the controller.
|
2
|
+
unless defined?($rails_rake_task) && $rails_rake_task
|
3
|
+
require 'resque'
|
4
|
+
require 'resque/version'
|
5
|
+
require 'digest/sha1'
|
4
6
|
|
5
7
|
|
6
|
-
class ResqueManager::ResqueController < ApplicationController
|
7
|
-
|
8
|
+
class ResqueManager::ResqueController < ApplicationController
|
9
|
+
unloadable(self) #needed to prevent errors with authenticated system in dev env.
|
8
10
|
|
9
|
-
|
11
|
+
layout 'resque_manager/application'
|
10
12
|
|
11
|
-
|
13
|
+
before_filter :check_connection
|
12
14
|
|
13
|
-
|
15
|
+
before_filter :get_cleaner, :only => [:cleaner, :cleaner_exec, :cleaner_list, :cleaner_stale, :cleaner_dump]
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
def queues
|
20
|
-
render('_queues', :locals => {:partial => nil})
|
21
|
-
end
|
17
|
+
def working
|
18
|
+
render('_working')
|
19
|
+
end
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
21
|
+
def queues
|
22
|
+
render('_queues', :locals => {:partial => nil})
|
23
|
+
end
|
27
24
|
|
28
|
-
|
29
|
-
|
25
|
+
def poll
|
26
|
+
@polling = true
|
27
|
+
render(:text => (render_to_string(:action => "#{params[:page]}", :formats => [:html], :layout => false, :resque => Resque)).gsub(/\s{1,}/, ' '))
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
@statuses = Resque::Plugins::Status::Hash.statuses(@start, @end)
|
34
|
-
@size = Resque::Plugins::Status::Hash.status_ids.size
|
30
|
+
def status_poll
|
31
|
+
@polling = true
|
35
32
|
|
36
|
-
|
37
|
-
|
33
|
+
@start = params[:start].to_i
|
34
|
+
@end = @start + (params[:per_page] || 20)
|
35
|
+
@statuses = Resque::Plugins::Status::Hash.statuses(@start, @end)
|
36
|
+
@size = Resque::Plugins::Status::Hash.status_ids.size
|
38
37
|
|
39
|
-
|
40
|
-
# We can only dequeue a job when that job is in the same application as the UI.
|
41
|
-
# Otherwise we get an error when we try to constantize a class that does not exist
|
42
|
-
# in the application the UI is in.
|
43
|
-
if ResqueManager.applications.blank?
|
44
|
-
Resque.dequeue(params['class'].constantize, *Resque.decode(params['args']))
|
38
|
+
render(:text => (render_to_string(:action => 'statuses', :formats => [:html], :layout => false)))
|
45
39
|
end
|
46
|
-
redirect_to request.referrer
|
47
|
-
end
|
48
|
-
|
49
|
-
def stop_worker
|
50
|
-
worker = find_worker(params[:worker])
|
51
|
-
worker.quit if worker
|
52
|
-
redirect_to workers_resque_path
|
53
|
-
end
|
54
40
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
41
|
+
def remove_job
|
42
|
+
# We can only dequeue a job when that job is in the same application as the UI.
|
43
|
+
# Otherwise we get an error when we try to constantize a class that does not exist
|
44
|
+
# in the application the UI is in.
|
45
|
+
if ResqueManager.applications.blank?
|
46
|
+
Resque.dequeue(params['class'].constantize, *Resque.decode(params['args']))
|
47
|
+
end
|
48
|
+
redirect_to request.referrer
|
49
|
+
end
|
60
50
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
51
|
+
def stop_worker
|
52
|
+
worker = find_worker(params[:worker])
|
53
|
+
worker.quit if worker
|
54
|
+
redirect_to workers_resque_path
|
55
|
+
end
|
66
56
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
57
|
+
def pause_worker
|
58
|
+
worker = find_worker(params[:worker])
|
59
|
+
worker.pause if worker
|
60
|
+
redirect_to workers_resque_path
|
61
|
+
end
|
72
62
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
63
|
+
def continue_worker
|
64
|
+
worker = find_worker(params[:worker])
|
65
|
+
worker.continue if worker
|
66
|
+
redirect_to workers_resque_path
|
67
|
+
end
|
77
68
|
|
78
|
-
|
79
|
-
|
80
|
-
|
69
|
+
def restart_worker
|
70
|
+
worker = find_worker(params[:worker])
|
71
|
+
worker.restart if worker
|
72
|
+
redirect_to workers_resque_path
|
81
73
|
end
|
82
74
|
|
83
|
-
|
84
|
-
|
75
|
+
def start_worker
|
76
|
+
Resque::Worker.start(params)
|
77
|
+
redirect_to workers_resque_path
|
78
|
+
end
|
85
79
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
stats << "resque.failed+=#{info[:failed]}"
|
90
|
-
stats << "resque.workers=#{info[:workers]}"
|
91
|
-
stats << "resque.working=#{info[:working]}"
|
92
|
-
Resque.queues.each do |queue|
|
93
|
-
stats << "queues.#{queue}=#{Resque.size(queue)}"
|
80
|
+
def stats
|
81
|
+
unless params[:id]
|
82
|
+
redirect_to(stats_resque_path(:id => 'resque'))
|
94
83
|
end
|
95
84
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
85
|
+
if params[:id] == 'txt'
|
86
|
+
info = Resque.info
|
87
|
+
|
88
|
+
stats = []
|
89
|
+
stats << "resque.pending=#{info[:pending]}"
|
90
|
+
stats << "resque.processed+=#{info[:processed]}"
|
91
|
+
stats << "resque.failed+=#{info[:failed]}"
|
92
|
+
stats << "resque.workers=#{info[:workers]}"
|
93
|
+
stats << "resque.working=#{info[:working]}"
|
94
|
+
Resque.queues.each do |queue|
|
95
|
+
stats << "queues.#{queue}=#{Resque.size(queue)}"
|
96
|
+
end
|
101
97
|
|
102
|
-
|
103
|
-
|
104
|
-
|
98
|
+
render(:text => stats.join("</br>").html_safe)
|
99
|
+
end
|
100
|
+
end
|
105
101
|
|
106
|
-
|
107
|
-
config = Resque.schedule[params['job_name']]
|
108
|
-
Resque::Scheduler.enqueue_from_config(config)
|
109
|
-
redirect_to overview_resque_path
|
110
|
-
end
|
102
|
+
# resque-scheduler actions
|
111
103
|
|
112
|
-
|
113
|
-
|
114
|
-
if Resque.schedule.keys.include?(params[:name])
|
115
|
-
errors << 'Name already exists.'
|
116
|
-
end
|
117
|
-
if params[:ip].blank?
|
118
|
-
errors << 'You must enter an ip address for the server you want this job to run on.'
|
104
|
+
def schedule
|
105
|
+
@farm_status = ResqueScheduler.farm_status
|
119
106
|
end
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
'ip' => params['ip'],
|
126
|
-
'cron' => params['cron'],
|
127
|
-
'args' => Resque.decode(params['args'].blank? ? nil : params['args']),
|
128
|
-
'description' => params['description']}
|
129
|
-
}
|
130
|
-
Resque.redis.rpush(:scheduled, Resque.encode(config))
|
131
|
-
ResqueScheduler.restart(params['ip'])
|
132
|
-
else
|
133
|
-
flash[:error] = errors.join('<br>').html_safe
|
107
|
+
|
108
|
+
def schedule_requeue
|
109
|
+
config = Resque.schedule[params['job_name']]
|
110
|
+
Resque::Scheduler.enqueue_from_config(config)
|
111
|
+
redirect_to overview_resque_path
|
134
112
|
end
|
135
|
-
redirect_to schedule_resque_path
|
136
|
-
end
|
137
113
|
|
138
|
-
|
139
|
-
|
140
|
-
if
|
141
|
-
|
142
|
-
|
114
|
+
def add_scheduled_job
|
115
|
+
errors = []
|
116
|
+
if Resque.schedule.keys.include?(params[:name])
|
117
|
+
errors << 'Name already exists.'
|
118
|
+
end
|
119
|
+
if params[:ip].blank?
|
120
|
+
errors << 'You must enter an ip address for the server you want this job to run on.'
|
121
|
+
end
|
122
|
+
if params[:cron].blank?
|
123
|
+
errors << 'You must enter the cron schedule.'
|
124
|
+
end
|
125
|
+
if errors.blank?
|
126
|
+
config = {params['name'] => {'class' => params['class'],
|
127
|
+
'ip' => params['ip'],
|
128
|
+
'cron' => params['cron'],
|
129
|
+
'args' => Resque.decode(params['args'].blank? ? nil : params['args']),
|
130
|
+
'description' => params['description']}
|
131
|
+
}
|
132
|
+
Resque.redis.rpush(:scheduled, Resque.encode(config))
|
143
133
|
ResqueScheduler.restart(params['ip'])
|
134
|
+
else
|
135
|
+
flash[:error] = errors.join('<br>').html_safe
|
144
136
|
end
|
137
|
+
redirect_to schedule_resque_path
|
145
138
|
end
|
146
|
-
redirect_to schedule_resque_path
|
147
|
-
end
|
148
139
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
140
|
+
def remove_from_schedule
|
141
|
+
Resque.list_range(:scheduled, 0, -0).each do |s|
|
142
|
+
if s[params['job_name']]
|
143
|
+
Resque.redis.lrem(:scheduled, 0, s.to_json)
|
144
|
+
# Restart the scheduler on the server that has changed it's schedule
|
145
|
+
ResqueScheduler.restart(params['ip'])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
redirect_to schedule_resque_path
|
149
|
+
end
|
153
150
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
151
|
+
def start_scheduler
|
152
|
+
ResqueScheduler.start(params[:ip])
|
153
|
+
redirect_to schedule_resque_path
|
154
|
+
end
|
155
|
+
|
156
|
+
def stop_scheduler
|
157
|
+
ResqueScheduler.quit(params[:ip])
|
158
|
+
redirect_to schedule_resque_path
|
159
|
+
end
|
158
160
|
|
159
|
-
|
161
|
+
# resque-status actions
|
160
162
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
163
|
+
def statuses
|
164
|
+
@start = params[:start].to_i
|
165
|
+
@end = @start + (params[:per_page] || 20)
|
166
|
+
@statuses = Resque::Plugins::Status::Hash.statuses(@start, @end)
|
167
|
+
@size = Resque::Plugins::Status::Hash.status_ids.size
|
168
|
+
respond_to do |format|
|
169
|
+
format.js { render json: @statuses }
|
170
|
+
format.html { render :statuses }
|
171
|
+
end
|
169
172
|
end
|
170
|
-
end
|
171
173
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
174
|
+
def clear_statuses
|
175
|
+
Resque::Plugins::Status::Hash.clear
|
176
|
+
redirect_to statuses_resque_path
|
177
|
+
end
|
176
178
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
179
|
+
def status
|
180
|
+
@status = Resque::Plugins::Status::Hash.get(params[:id])
|
181
|
+
respond_to do |format|
|
182
|
+
format.js { render json: @status }
|
183
|
+
format.html { render :status }
|
184
|
+
end
|
182
185
|
end
|
183
|
-
end
|
184
186
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
187
|
+
def kill
|
188
|
+
Resque::Plugins::Status::Hash.kill(params[:id])
|
189
|
+
s = Resque::Plugins::Status::Hash.get(params[:id])
|
190
|
+
s.status = 'killed'
|
191
|
+
Resque::Plugins::Status::Hash.set(params[:id], s)
|
192
|
+
redirect_to statuses_resque_path
|
193
|
+
end
|
192
194
|
|
193
|
-
|
194
|
-
|
195
|
+
def cleaner
|
196
|
+
load_cleaner_filter
|
195
197
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
198
|
+
@jobs = @cleaner.select
|
199
|
+
@stats, @total = {}, {"total" => 0, "1h" => 0, "3h" => 0, "1d" => 0, "3d" => 0, "7d" => 0}
|
200
|
+
@jobs.each do |job|
|
201
|
+
klass = job["payload"]["class"]
|
202
|
+
failed_at = Time.parse job["failed_at"]
|
201
203
|
|
202
|
-
|
203
|
-
|
204
|
+
@stats[klass] ||= {"total" => 0, "1h" => 0, "3h" => 0, "1d" => 0, "3d" => 0, "7d" => 0}
|
205
|
+
items = [@stats[klass], @total]
|
204
206
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
207
|
+
items.each { |a| a["total"] += 1 }
|
208
|
+
items.each { |a| a["1h"] += 1 } if failed_at >= hours_ago(1)
|
209
|
+
items.each { |a| a["3h"] += 1 } if failed_at >= hours_ago(3)
|
210
|
+
items.each { |a| a["1d"] += 1 } if failed_at >= hours_ago(24)
|
211
|
+
items.each { |a| a["3d"] += 1 } if failed_at >= hours_ago(24*3)
|
212
|
+
items.each { |a| a["7d"] += 1 } if failed_at >= hours_ago(24*7)
|
213
|
+
end
|
211
214
|
end
|
212
|
-
end
|
213
215
|
|
214
|
-
|
215
|
-
|
216
|
+
def cleaner_list
|
217
|
+
load_cleaner_filter
|
216
218
|
|
217
|
-
|
219
|
+
block = filter_block
|
218
220
|
|
219
|
-
|
221
|
+
@failed = @cleaner.select(&block).reverse
|
220
222
|
|
221
|
-
|
222
|
-
|
223
|
-
|
223
|
+
url = "cleaner_list?c=#{@klass}&ex=#{@exception}&f=#{@from}&t=#{@to}"
|
224
|
+
@dump_url = "cleaner_dump?c=#{@klass}&ex=#{@exception}&f=#{@from}&t=#{@to}"
|
225
|
+
@paginate = ResqueManager::Paginate.new(@failed, url, params[:p].to_i)
|
224
226
|
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
227
|
+
@klasses = @cleaner.stats_by_class.keys
|
228
|
+
@exceptions = @cleaner.stats_by_exception.keys
|
229
|
+
@count = @cleaner.select(&block).size
|
230
|
+
end
|
229
231
|
|
230
|
-
|
231
|
-
|
232
|
+
def cleaner_exec
|
233
|
+
load_cleaner_filter
|
232
234
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
235
|
+
if params[:select_all_pages]!="1"
|
236
|
+
@sha1 = {}
|
237
|
+
params[:sha1].split(",").each { |s| @sha1[s] = true }
|
238
|
+
end
|
237
239
|
|
238
|
-
|
240
|
+
block = filter_block
|
239
241
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
242
|
+
@count =
|
243
|
+
case params[:form_action]
|
244
|
+
when "clear" then
|
245
|
+
@cleaner.clear(&block)
|
246
|
+
when "retry_and_clear" then
|
247
|
+
@cleaner.requeue(true, &block)
|
248
|
+
when "retry" then
|
249
|
+
@cleaner.requeue(false, {}, &block)
|
250
|
+
end
|
249
251
|
|
250
|
-
|
251
|
-
|
252
|
+
@link_url = "cleaner_list?c=#{@klass}&ex=#{@exception}&f=#{@from}&t=#{@to}"
|
253
|
+
end
|
252
254
|
|
253
|
-
|
254
|
-
|
255
|
+
def cleaner_dump
|
256
|
+
load_cleaner_filter
|
255
257
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
258
|
+
block = filter_block
|
259
|
+
failures = @cleaner.select(&block)
|
260
|
+
# pretty generate throws an error with the json gem on jruby
|
261
|
+
output = JSON.pretty_generate(failures) rescue failures.to_json
|
262
|
+
render :json => output
|
263
|
+
end
|
262
264
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
265
|
+
def cleaner_stale
|
266
|
+
@cleaner.clear_stale
|
267
|
+
redirect_to cleaner_resque_path
|
268
|
+
end
|
267
269
|
|
268
270
|
|
269
|
-
|
271
|
+
private
|
270
272
|
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
273
|
+
def check_connection
|
274
|
+
Resque.keys
|
275
|
+
rescue Errno::ECONNREFUSED
|
276
|
+
render(:template => 'resque_manager/resque/error', :layout => false, :locals => {:error => "Can't connect to Redis! (#{Resque.redis_id})"})
|
277
|
+
false
|
278
|
+
end
|
277
279
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
280
|
+
def find_worker(worker)
|
281
|
+
return nil if worker.blank?
|
282
|
+
first_part, *rest = worker.split(':')
|
283
|
+
first_part.gsub!(/_/, '.')
|
284
|
+
Resque::Worker.find("#{first_part}:#{rest.join(':')}")
|
285
|
+
end
|
284
286
|
|
285
|
-
|
287
|
+
# resque-cleaner methods
|
286
288
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
289
|
+
def get_cleaner
|
290
|
+
@cleaner ||= Resque::Plugins::ResqueCleaner.new
|
291
|
+
@cleaner.print_message = false
|
292
|
+
@cleaner
|
293
|
+
end
|
292
294
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
295
|
+
def load_cleaner_filter
|
296
|
+
@from = params[:f].blank? ? nil : params[:f]
|
297
|
+
@to = params[:t].blank? ? nil : params[:t]
|
298
|
+
@klass = params[:c].blank? ? nil : params[:c]
|
299
|
+
@exception = params[:ex].blank? ? nil : params[:ex]
|
300
|
+
end
|
299
301
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
302
|
+
def filter_block
|
303
|
+
lambda { |j|
|
304
|
+
(!@from || j.after?(hours_ago(@from))) &&
|
305
|
+
(!@to || j.before?(hours_ago(@to))) &&
|
306
|
+
(!@klass || j.klass?(@klass)) &&
|
307
|
+
(!@exception || j.exception?(@exception)) &&
|
308
|
+
(!@sha1 || @sha1[Digest::SHA1.hexdigest(j.to_json)])
|
309
|
+
}
|
310
|
+
end
|
309
311
|
|
310
|
-
|
311
|
-
|
312
|
+
def hours_ago(h)
|
313
|
+
Time.now - h.to_i*60*60
|
314
|
+
end
|
312
315
|
end
|
313
|
-
end
|
316
|
+
end
|