resque_ui 3.1.7 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +6 -0
- data/README.markdown +93 -4
- data/VERSION.yml +2 -2
- data/app/controllers/resque_controller.rb +12 -0
- data/app/views/resque/_workers.html.erb +115 -95
- data/lib/resque_ui/cap_recipes.rb +21 -1
- data/lib/resque_ui/overrides/resque/job.rb +66 -2
- data/lib/resque_ui/overrides/resque/worker.rb +72 -10
- data/lib/resque_ui/overrides/resque_status/job_with_status.rb +45 -1
- data/lib/resque_ui/overrides/resque_status/status.rb +5 -0
- data/rdoc/Resque/Job.html +68 -4
- data/rdoc/Resque/JobWithStatus.html +161 -7
- data/rdoc/Resque/Status.html +47 -5
- data/rdoc/Resque/Worker.html +313 -64
- data/rdoc/created.rid +8 -8
- data/rdoc/index.html +27 -7
- data/rdoc/lib/resque_ui/cap_rb.html +1 -1
- data/rdoc/lib/resque_ui/cap_recipes_rb.html +2 -2
- data/rdoc/lib/resque_ui/overrides/resque/job_rb.html +2 -2
- data/rdoc/lib/resque_ui/overrides/resque/resque_rb.html +1 -1
- data/rdoc/lib/resque_ui/overrides/resque/worker_rb.html +2 -2
- data/rdoc/lib/resque_ui/overrides/resque_scheduler/resque_scheduler_rb.html +1 -1
- data/rdoc/lib/resque_ui/overrides/resque_status/chained_job_with_status_rb.html +1 -1
- data/rdoc/lib/resque_ui/overrides/resque_status/job_with_status_rb.html +2 -2
- data/rdoc/lib/resque_ui/overrides/resque_status/status_rb.html +2 -2
- data/rdoc/lib/resque_ui_rb.html +2 -2
- data/resque_ui.gemspec +2 -2
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 3.2.0 2011-11-14
|
2
|
+
|
3
|
+
* Added the ability to pause workers from the UI.
|
4
|
+
* If the worker is processing a job, it will pause the job on the next call to tick.
|
5
|
+
* JobWithStatus class now exposed the worker so the job can manually inspect the worker's status if necessary.
|
6
|
+
|
1
7
|
== 3.1.7 2011-11-03
|
2
8
|
|
3
9
|
* It seems that when jruby workers are started in server mode, they don't accept the -INT signal.
|
data/README.markdown
CHANGED
@@ -49,15 +49,16 @@ Display Process Status
|
|
49
49
|
----------------------
|
50
50
|
|
51
51
|
Added the ability to display process status in the worker "Processing" column on the workers and working pages.
|
52
|
-
To do this, yield the status message back in your perform method.
|
52
|
+
To do this, yield the status message back in your perform method. You should check that a block was sent. If you
|
53
|
+
set Resque.inline = true in development, then the block is not passed.
|
53
54
|
|
54
55
|
Class YourClass
|
55
56
|
|
56
57
|
self.perform(arg)
|
57
58
|
...your code here
|
58
|
-
yield "Your status message"
|
59
|
+
yield "Your status message" if block_given?
|
59
60
|
...more code
|
60
|
-
yield "Another status message"
|
61
|
+
yield "Another status message" if block_given?
|
61
62
|
...more code
|
62
63
|
end
|
63
64
|
end
|
@@ -128,7 +129,7 @@ the chained job from the preceding job, you just need to pass {'uuid' => uuid} a
|
|
128
129
|
end
|
129
130
|
|
130
131
|
So now, the data_contribution worker and the single_record_loader workers will update the same status on the status page.
|
131
|
-
You can call tick or set_status to add messages along the way too.
|
132
|
+
You can call #tick or #set_status to add messages along the way too.
|
132
133
|
|
133
134
|
You will want to override the completed method so that it isn't called until the very end of the entire process.
|
134
135
|
|
@@ -141,6 +142,94 @@ symbol to read the integer back. The redis entries created by these methods all
|
|
141
142
|
|
142
143
|
When you kill a job on the UI, it will kill all the workers in the chain.
|
143
144
|
|
145
|
+
Pause a Worker
|
146
|
+
--------------
|
147
|
+
|
148
|
+
The workers page now has a button for every worker to pause that worker.
|
149
|
+
|
150
|
+
### Regular Workers
|
151
|
+
|
152
|
+
For workers that do not inherit from JobWithStatus, this will pause the worker, but not the job. So if the worker is in
|
153
|
+
the middle of a job when it is paused, it will finish it's process, but then will not pick anything else up off the queue.
|
154
|
+
|
155
|
+
You can manually pause the processing though.
|
156
|
+
|
157
|
+
yield, which is used to set the workers status, as described above, now returns the worker.
|
158
|
+
|
159
|
+
Class YourClass
|
160
|
+
|
161
|
+
self.perform(arg)
|
162
|
+
...your code here
|
163
|
+
worker = yield "Your status message" if block_given?
|
164
|
+
|
165
|
+
if worker && worker.paused?
|
166
|
+
loop do
|
167
|
+
break unless worker.paused?
|
168
|
+
sleep 60
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
...continue
|
174
|
+
end
|
175
|
+
|
176
|
+
Remember to check that a block was sent. If you set Resque.inline = true in development, then the block is not passed.
|
177
|
+
|
178
|
+
|
179
|
+
### JobWithStatus Workers
|
180
|
+
|
181
|
+
For workers that do inherit from JobWithStatus or ChainedJobWithStatus, this will pause the worker, and will automatically pause the job it is processing
|
182
|
+
on the next call to #tick. The worker is also available to JobWithStatus so you can manually check it's status as well.
|
183
|
+
|
184
|
+
Class YourClass << Resque::JobWithStatus
|
185
|
+
|
186
|
+
def perform
|
187
|
+
...your code here
|
188
|
+
tick "Retrieving file." #You're process with pause here automatically and the status on the Status tab will be set to paused if the worker is paused.
|
189
|
+
|
190
|
+
#Alternatively, you have access to the worker, so you can pause the process yourself too.
|
191
|
+
if worker && worker.paused?
|
192
|
+
# There could be workers in a chained job still doing work.
|
193
|
+
loop do
|
194
|
+
pause! unless status.paused?
|
195
|
+
break unless worker.paused?
|
196
|
+
sleep 60
|
197
|
+
end
|
198
|
+
tick("Job resumed at #{Time.now}")
|
199
|
+
end
|
200
|
+
|
201
|
+
...continue
|
202
|
+
end
|
203
|
+
|
204
|
+
This will only pause the work being processed by the worker that was paused. If the job is paused by the call to #tick,
|
205
|
+
the job will sleep for 60 seconds before checking the status again.
|
206
|
+
|
207
|
+
You may have a series of ChainedJobWithStatus and you want all processing in the chain stopped.
|
208
|
+
|
209
|
+
Class YourClass << Resque::ChainedJobWithStatus
|
210
|
+
|
211
|
+
def perform
|
212
|
+
...your code here
|
213
|
+
tick "Retrieving file." #You're process with pause here automatically and the status on the Status tab will be set to paused if the worker is paused.
|
214
|
+
|
215
|
+
#Alternatively, you have access to the worker, so you can pause the process yourself too.
|
216
|
+
if (worker && worker.paused?) || status.paused?
|
217
|
+
# There could be workers in a chained job still doing work.
|
218
|
+
loop do
|
219
|
+
pause! unless status.paused?
|
220
|
+
break unless worker.paused?
|
221
|
+
sleep 60
|
222
|
+
end
|
223
|
+
tick("Job resumed at #{Time.now}")
|
224
|
+
end
|
225
|
+
|
226
|
+
...continue
|
227
|
+
end
|
228
|
+
|
229
|
+
By looking at the status.paused? method too, this process will stop, even if it's worker has not been paused.
|
230
|
+
But be aware, if this worker does other jobs, it will not process anything else and it's queue could get backed up.
|
231
|
+
This is where pausing one worker, could affect other, unrelated workers and jobs from getting backed up as well.
|
232
|
+
|
144
233
|
Throttle a Queue
|
145
234
|
----------------
|
146
235
|
|
data/VERSION.yml
CHANGED
@@ -58,6 +58,18 @@ class ResqueController < ApplicationController
|
|
58
58
|
redirect_to(:action => "workers")
|
59
59
|
end
|
60
60
|
|
61
|
+
def pause_worker
|
62
|
+
worker = find_worker(params[:worker])
|
63
|
+
worker.pause if worker
|
64
|
+
redirect_to(:action => "workers")
|
65
|
+
end
|
66
|
+
|
67
|
+
def continue_worker
|
68
|
+
worker = find_worker(params[:worker])
|
69
|
+
worker.continue if worker
|
70
|
+
redirect_to(:action => "workers")
|
71
|
+
end
|
72
|
+
|
61
73
|
def restart_worker
|
62
74
|
worker = find_worker(params[:worker])
|
63
75
|
worker.restart if worker
|
@@ -1,110 +1,130 @@
|
|
1
|
-
|
2
1
|
<% if params[:id] && worker = find_worker(params[:id]) %>
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
<
|
3
|
+
<h1>Worker <%= worker %></h1>
|
4
|
+
<table class='workers'>
|
5
|
+
<tr>
|
6
|
+
<th> </th>
|
7
|
+
<th>Host</th>
|
8
|
+
<th>Pid</th>
|
9
|
+
<th>Thread</th>
|
10
|
+
<th>Started</th>
|
11
|
+
<th>Paused</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'>
|
19
|
+
<img src="<%= u "../../images/resque/#{state = worker.state}" %>.png" alt="<%= state %>" title="<%= state %>">
|
20
|
+
</td>
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<td class='process'>
|
29
|
-
<% data = worker.processing || {} %>
|
30
|
-
<% if data['queue'] %>
|
31
|
-
<code><%= data['payload']['class'] %></code>
|
32
|
-
<small><%= link_to(format_time(Time.zone.parse(data['run_at'])), {:action => 'working', :id => worker.to_s.gsub(/\./,'_')}, :class => "queue time") %></small>
|
33
|
-
<br>
|
34
|
-
<small><%=worker.status%></small>
|
22
|
+
<% host, pid, thread, queues = worker.to_s.split(':') %>
|
23
|
+
<td><%= host %></td>
|
24
|
+
<td><%= pid %></td>
|
25
|
+
<td><%= thread %></td>
|
26
|
+
<td><span class="time"><%= format_time(Time.zone.parse(worker.started)) %></span></td>
|
27
|
+
<td>
|
28
|
+
<% if worker.paused? %>
|
29
|
+
<span class="time"><%= format_time(Time.zone.parse(worker.paused)) %></span>
|
35
30
|
<% else %>
|
36
|
-
|
31
|
+
<span>Not Paused</span>
|
37
32
|
<% end %>
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
<% elsif params[:id] %>
|
43
|
-
|
44
|
-
<h1>Worker doesn't exist</h1>
|
45
|
-
|
46
|
-
<% else %>
|
47
|
-
|
48
|
-
<h1 class='wi'><%= pluralize resque.workers.size, 'Worker' %></h1>
|
49
|
-
<p class='intro'>The workers listed below are all registered as active on your system.</p>
|
50
|
-
<table class='workers'>
|
51
|
-
<tr>
|
52
|
-
<th> </th>
|
53
|
-
<th>Where (ip):pid:thread</th>
|
54
|
-
<th>Queues</th>
|
55
|
-
<th>Processing</th>
|
56
|
-
<th> </th>
|
57
|
-
</tr>
|
58
|
-
<% upid = ''%>
|
59
|
-
<% for worker in (workers = resque.workers.sort_by { |w| w.to_s }) %>
|
60
|
-
<tr class="<%=state = worker.state%>">
|
61
|
-
<td class='icon'><img src="<%=u "../../images/resque/#{state}" %>.png" alt="<%= state %>" title="<%= state %>"></td>
|
62
|
-
|
63
|
-
<% host, pid, thread, queues = worker.to_s.split(':') %>
|
64
|
-
<td class='where'><%=link_to("#{host}:#{pid}:#{thread}",:action => 'workers', :id => worker.to_s.gsub(/\./,'_'))%></td>
|
65
|
-
<td class='queues'><%= queues.split(',').map { |q| link_to(q, {:action => 'queues', :id => q}, :class => 'queue-tag')}.join('').html_safe %></td>
|
66
|
-
|
33
|
+
</td>
|
34
|
+
<td class='queues'><%= queues.split(',').map { |q| link_to(q, {:action => 'queues', :id => q}, :class => 'queue-tag') }.join('').html_safe %></td>
|
35
|
+
<td><%= worker.processed %></td>
|
36
|
+
<td><%= worker.failed %></td>
|
67
37
|
<td class='process'>
|
68
38
|
<% data = worker.processing || {} %>
|
69
39
|
<% if data['queue'] %>
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
40
|
+
<code><%= data['payload']['class'] %></code>
|
41
|
+
<small><%= link_to(format_time(Time.zone.parse(data['run_at'])), {:action => 'working', :id => worker.to_s.gsub(/\./, '_')}, :class => "queue time") %></small>
|
42
|
+
<br>
|
43
|
+
<small><%= worker.status %></small>
|
74
44
|
<% else %>
|
75
|
-
|
76
|
-
<% end %>
|
77
|
-
</td>
|
78
|
-
<td>
|
79
|
-
<% if upid != pid %>
|
80
|
-
<%= button_to "Stop", {:controller=>'resque', :action=> 'stop_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will stop all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect{|w| w.to_s}.join(', ')}", :method => :post %>
|
81
|
-
<%= button_to "Restart", {:controller=>'resque', :action=> 'restart_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will restart all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect{|w| w.to_s}.join(', ')}", :method => :post %>
|
82
|
-
<% upid = pid %>
|
45
|
+
<span class='waiting'>Waiting for a job...</span>
|
83
46
|
<% end %>
|
84
47
|
</td>
|
85
48
|
</tr>
|
86
|
-
|
87
|
-
|
49
|
+
</table>
|
50
|
+
|
51
|
+
<% elsif params[:id] %>
|
52
|
+
|
53
|
+
<h1>Worker doesn't exist</h1>
|
54
|
+
|
55
|
+
<% else %>
|
56
|
+
|
57
|
+
<h1 class='wi'><%= pluralize resque.workers.size, 'Worker' %></h1>
|
58
|
+
<p class='intro'>The workers listed below are all registered as active on your system.</p>
|
59
|
+
<table class='workers'>
|
88
60
|
<tr>
|
89
|
-
<
|
61
|
+
<th> </th>
|
62
|
+
<th>Where (ip):pid:thread</th>
|
63
|
+
<th>Queues</th>
|
64
|
+
<th>Processing</th>
|
65
|
+
<th> </th>
|
90
66
|
</tr>
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
67
|
+
<% upid = '' %>
|
68
|
+
<% for worker in (workers = resque.workers.sort_by { |w| w.to_s }) %>
|
69
|
+
<tr class="<%= state = worker.state %>">
|
70
|
+
<td class='icon'>
|
71
|
+
<img src="<%= u "../../images/resque/#{state}" %>.png" alt="<%= state %>" title="<%= state %>"></td>
|
72
|
+
|
73
|
+
<% host, pid, thread, queues = worker.to_s.split(':') %>
|
74
|
+
<td class='where'><%= link_to("#{host}:#{pid}:#{thread}", :action => 'workers', :id => worker.to_s.gsub(/\./, '_')) %></td>
|
75
|
+
<td class='queues'><%= queues.split(',').map { |q| link_to(q, {:action => 'queues', :id => q}, :class => 'queue-tag') }.join('').html_safe %></td>
|
76
|
+
|
77
|
+
<td class='process'>
|
78
|
+
<% data = worker.processing || {} %>
|
79
|
+
<% if data['queue'] %>
|
80
|
+
<code><%= data['payload']['class'] %></code>
|
81
|
+
<small><%= link_to(format_time(Time.zone.parse(data['run_at'])), {:action => 'working', :id => worker.to_s.gsub(/\./, '_')}, :class => "queue time") %></small>
|
82
|
+
<br/>
|
83
|
+
<small><%= worker.status %></small>
|
84
|
+
<% else %>
|
85
|
+
<span class='waiting'>Waiting for a job...</span>
|
86
|
+
<% end %>
|
87
|
+
</td>
|
88
|
+
<td>
|
89
|
+
<% if upid != pid %>
|
90
|
+
<%= button_to "Stop", {:controller=>'resque', :action=> 'stop_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will stop all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
|
91
|
+
<% if worker.paused? %>
|
92
|
+
<%= button_to "Unpause", {:controller=>'resque', :action=> 'continue_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will unpause all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
|
93
|
+
<% else %>
|
94
|
+
<%= button_to "Pause", {:controller=>'resque', :action=> 'pause_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will pause all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
|
95
|
+
<% end %>
|
96
|
+
<%= button_to "Restart", {:controller=>'resque', :action=> 'restart_worker', :worker => worker.to_s}, :class => 'clear-failed', :title => "This will restart all workers on #{host} in pid #{pid}: #{worker.workers_in_pid.collect { |w| w.to_s }.join(', ')}", :method => :post %>
|
97
|
+
<% upid = pid %>
|
98
|
+
<% end %>
|
99
|
+
</td>
|
100
|
+
</tr>
|
101
|
+
<% end %>
|
102
|
+
<% if workers.empty? %>
|
103
|
+
<tr>
|
104
|
+
<td colspan='5' class='no-data'>There are no registered workers</td>
|
105
|
+
</tr>
|
106
|
+
<% end %>
|
107
|
+
</table>
|
108
|
+
<%= poll %>
|
109
|
+
<br/>
|
110
|
+
<hr/>
|
111
|
+
<h1 class='wi'>Start New Workers</h1>
|
112
|
+
<%= form_tag :action => 'start_worker' do -%>
|
113
|
+
<ul class='new_worker'>
|
114
|
+
<li>
|
115
|
+
<dl>
|
116
|
+
<dt>Queue(s)</dt>
|
117
|
+
<dd><%= text_field_tag :queues, nil, :size => 125 %>
|
118
|
+
<br/> Prefix each worker with a '#', comma separate the list of queues you want each worker to monitor.
|
119
|
+
No Spaces. #queue1,queue2#queue3#queue2 will produce 3 workers in 3 threads.
|
120
|
+
</dd>
|
121
|
+
<dt>Host(s)/IP(s)</dt>
|
122
|
+
<dd><%= text_field_tag :hosts, nil, :size => 125 %>
|
123
|
+
<br/> Comma separate the IP address of the servers where you want your worker to run.
|
124
|
+
</dd>
|
125
|
+
<dt><%= submit_tag "Start", :id => "submit" %></dt>
|
126
|
+
</dl>
|
127
|
+
</li>
|
128
|
+
</ul>
|
129
|
+
<% end -%>
|
110
130
|
<% end %>
|
@@ -68,7 +68,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
68
68
|
desc "Gracefully kill a worker. If the worker is working, it will finish before shutting down. arg: host=ip pid=pid"
|
69
69
|
task :quit_worker, :roles => :resque do
|
70
70
|
if ENV['host'].nil? || ENV['host'].empty? || ENV['pid'].nil? || ENV['pid'].empty?
|
71
|
-
puts 'You must enter the host and pid to kill..cap resque:
|
71
|
+
puts 'You must enter the host and pid to kill..cap resque:quit_worker host=ip pid=pid'
|
72
72
|
else
|
73
73
|
hosts = ENV['host'] || find_servers_for_task(current_task).collect { |s| s.host }
|
74
74
|
if RUBY_PLATFORM =~ /java/
|
@@ -82,6 +82,26 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
desc "Pause all workers in a single process. arg: host=ip pid=pid"
|
86
|
+
task :pause_worker, :roles => :resque do
|
87
|
+
if ENV['host'].nil? || ENV['host'].empty? || ENV['pid'].nil? || ENV['pid'].empty?
|
88
|
+
puts 'You must enter the host and pid to kill..cap resque:pause_worker host=ip pid=pid'
|
89
|
+
else
|
90
|
+
hosts = ENV['host'] || find_servers_for_task(current_task).collect { |s| s.host }
|
91
|
+
run("kill -USR2 #{ENV['pid']}", :hosts => hosts)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
desc "Continue all workers in a single process that have been paused. arg: host=ip pid=pid"
|
96
|
+
task :continue_worker, :roles => :resque do
|
97
|
+
if ENV['host'].nil? || ENV['host'].empty? || ENV['pid'].nil? || ENV['pid'].empty?
|
98
|
+
puts 'You must enter the host and pid to kill..cap resque:continue_worker host=ip pid=pid'
|
99
|
+
else
|
100
|
+
hosts = ENV['host'] || find_servers_for_task(current_task).collect { |s| s.host }
|
101
|
+
run("kill -CONT #{ENV['pid']}", :hosts => hosts)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
85
105
|
desc "Gracefully kill all workers on all servers. If the worker is working, it will finish before shutting down."
|
86
106
|
task :quit_workers, :roles => :resque do
|
87
107
|
default_run_options[:pty] = true
|
@@ -3,9 +3,73 @@ module Resque
|
|
3
3
|
# Attempts to perform the work represented by this job instance.
|
4
4
|
# Calls #perform on the class given in the payload with the
|
5
5
|
# arguments given in the payload.
|
6
|
-
#
|
6
|
+
# A block is sent so a message can be yielded back to be set in the worker.
|
7
7
|
def perform
|
8
|
-
|
8
|
+
job = payload_class
|
9
|
+
job_args = args || []
|
10
|
+
job_was_performed = false
|
11
|
+
|
12
|
+
before_hooks = Plugin.before_hooks(job)
|
13
|
+
around_hooks = Plugin.around_hooks(job)
|
14
|
+
after_hooks = Plugin.after_hooks(job)
|
15
|
+
failure_hooks = Plugin.failure_hooks(job)
|
16
|
+
|
17
|
+
begin
|
18
|
+
# Execute before_perform hook. Abort the job gracefully if
|
19
|
+
# Resque::DontPerform is raised.
|
20
|
+
begin
|
21
|
+
before_hooks.each do |hook|
|
22
|
+
job.send(hook, *job_args)
|
23
|
+
end
|
24
|
+
rescue DontPerform
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Execute the job. Do it in an around_perform hook if available.
|
29
|
+
if around_hooks.empty?
|
30
|
+
job.perform(*job_args) do |status|
|
31
|
+
self.worker.status = status if status.present?
|
32
|
+
self.worker
|
33
|
+
end
|
34
|
+
job_was_performed = true
|
35
|
+
else
|
36
|
+
# We want to nest all around_perform plugins, with the last one
|
37
|
+
# finally calling perform
|
38
|
+
stack = around_hooks.reverse.inject(nil) do |last_hook, hook|
|
39
|
+
if last_hook
|
40
|
+
lambda do
|
41
|
+
job.send(hook, *job_args) { last_hook.call }
|
42
|
+
end
|
43
|
+
else
|
44
|
+
lambda do
|
45
|
+
job.send(hook, *job_args) do
|
46
|
+
result = job.perform(*job_args) do |status|
|
47
|
+
self.worker.status = status if status.present?
|
48
|
+
self.worker
|
49
|
+
end
|
50
|
+
job_was_performed = true
|
51
|
+
result
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
stack.call
|
57
|
+
end
|
58
|
+
|
59
|
+
# Execute after_perform hook
|
60
|
+
after_hooks.each do |hook|
|
61
|
+
job.send(hook, *job_args)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Return true if the job was performed
|
65
|
+
return job_was_performed
|
66
|
+
|
67
|
+
# If an exception occurs during the job execution, look for an
|
68
|
+
# on_failure hook then re-raise.
|
69
|
+
rescue Object => e
|
70
|
+
failure_hooks.each { |hook| job.send(hook, e, *job_args) }
|
71
|
+
raise e
|
72
|
+
end
|
9
73
|
end
|
10
74
|
|
11
75
|
end
|