resque 1.27.3 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of resque might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/HISTORY.md +74 -1
- data/README.markdown +421 -486
- data/bin/resque-web +1 -1
- data/lib/resque/data_store.rb +23 -31
- data/lib/resque/errors.rb +7 -1
- data/lib/resque/failure/airbrake.rb +19 -7
- data/lib/resque/failure/multiple.rb +6 -2
- data/lib/resque/failure/redis.rb +1 -1
- data/lib/resque/failure/redis_multi_queue.rb +3 -3
- data/lib/resque/failure.rb +7 -0
- data/lib/resque/job.rb +2 -2
- data/lib/resque/logging.rb +1 -1
- data/lib/resque/railtie.rb +10 -0
- data/lib/resque/server/helpers.rb +3 -1
- data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
- data/lib/resque/server/public/main.js +3 -0
- data/lib/resque/server/public/ranger.js +7 -4
- data/lib/resque/server/public/style.css +3 -3
- data/lib/resque/server/test_helper.rb +1 -1
- data/lib/resque/server/views/failed.erb +8 -2
- data/lib/resque/server/views/failed_job.erb +2 -2
- data/lib/resque/server/views/layout.erb +4 -3
- data/lib/resque/server/views/next_more.erb +14 -14
- data/lib/resque/server/views/queues.erb +6 -6
- data/lib/resque/server/views/stats.erb +1 -1
- data/lib/resque/server/views/working.erb +6 -6
- data/lib/resque/server.rb +12 -9
- data/lib/resque/stat.rb +12 -5
- data/lib/resque/tasks.rb +1 -9
- data/lib/resque/thread_signal.rb +13 -34
- data/lib/resque/vendor/utf8_util.rb +2 -8
- data/lib/resque/version.rb +1 -1
- data/lib/resque/worker.rb +55 -36
- data/lib/resque.rb +92 -18
- metadata +16 -15
- data/lib/resque/server/public/jquery-1.12.4.min.js +0 -5
- data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -6
@@ -6,10 +6,10 @@
|
|
6
6
|
<% else %>
|
7
7
|
<dt>Worker</dt>
|
8
8
|
<dd>
|
9
|
-
<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"><%=
|
9
|
+
<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"><%= DateTime.parse(job['failed_at']).strftime(failed_date_format) %></span></b>
|
10
10
|
<% if job['retried_at'] %>
|
11
11
|
<div class='retried'>
|
12
|
-
Retried <b><span class="time"><%=
|
12
|
+
Retried <b><span class="time"><%= DateTime.parse(job['retried_at']).strftime(failed_date_format) %></span></b>
|
13
13
|
<a href="<%= u "#{queue}/remove/#{id}" %>" class="remove" rel="remove">Remove</a>
|
14
14
|
</div>
|
15
15
|
<% else %>
|
@@ -5,9 +5,10 @@
|
|
5
5
|
<title>Resque</title>
|
6
6
|
<link href="<%=u 'reset.css' %>" media="screen" rel="stylesheet" type="text/css">
|
7
7
|
<link href="<%=u 'style.css' %>" media="screen" rel="stylesheet" type="text/css">
|
8
|
-
<script src="<%=u 'jquery-
|
8
|
+
<script src="<%=u 'jquery-3.6.0.min.js' %>" type="text/javascript"></script>
|
9
9
|
<script src="<%=u 'jquery.relatize_date.js' %>" type="text/javascript"></script>
|
10
10
|
<script src="<%=u 'ranger.js' %>" type="text/javascript"></script>
|
11
|
+
<script src="<%=u 'main.js' %>" type="text/javascript"></script>
|
11
12
|
</head>
|
12
13
|
<body>
|
13
14
|
<div class="header">
|
@@ -23,7 +24,7 @@
|
|
23
24
|
<% end %>
|
24
25
|
</div>
|
25
26
|
|
26
|
-
<% if @subtabs %>
|
27
|
+
<% if defined?(@subtabs) && @subtabs %>
|
27
28
|
<ul class='subnav'>
|
28
29
|
<% for subtab in @subtabs %>
|
29
30
|
<li <%= class_if_current "#{current_section}/#{subtab}" %>><a href="<%= current_section %>/<%= subtab %>"><span><%= subtab %></span></a></li>
|
@@ -36,7 +37,7 @@
|
|
36
37
|
</div>
|
37
38
|
|
38
39
|
<div id="footer">
|
39
|
-
<p>Powered by <a href="http://github.com/resque/resque">Resque</a> v<%=Resque::
|
40
|
+
<p>Powered by <a href="http://github.com/resque/resque">Resque</a> v<%=Resque::VERSION%></p>
|
40
41
|
<p>Connected to Redis namespace <%= Resque.redis.namespace %> on <%=Resque.redis_id%></p>
|
41
42
|
</div>
|
42
43
|
|
@@ -2,21 +2,21 @@
|
|
2
2
|
<% # without a default value %>
|
3
3
|
<% per_page ||= 20 %>
|
4
4
|
<%if start - per_page >= 0 || start + per_page <= size%>
|
5
|
-
<
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
<div class='pagination'>
|
6
|
+
<% if start - per_page >= 0 %>
|
7
|
+
<a href="<%= current_page %>?start=<%= start - per_page %>" class='less'>« Previous</a>
|
8
|
+
<% end %>
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
<% (size / per_page.to_f - 1).ceil.times do |page_num| %>
|
11
|
+
<% if start == page_num * per_page %>
|
12
|
+
<span><%= page_num + 1 %></span>
|
13
|
+
<% else %>
|
14
|
+
<a href="<%= current_page %>?start=<%= page_num * per_page %>"> <%= page_num + 1 %></a>
|
15
|
+
<% end %>
|
15
16
|
<% end %>
|
16
|
-
<% end %>
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
</
|
18
|
+
<% if start + per_page <= size %>
|
19
|
+
<a href="<%= current_page %>?start=<%= start + per_page %>" class='more'>Next »</a>
|
20
|
+
<% end %>
|
21
|
+
</div>
|
22
22
|
<%end%>
|
@@ -1,18 +1,18 @@
|
|
1
1
|
<% @subtabs = resque.queues unless partial? || params[:id].nil? %>
|
2
2
|
|
3
|
-
<% if
|
3
|
+
<% if current_queue = params[:id] %>
|
4
4
|
|
5
|
-
<h1>Pending jobs on <span class='hl'><%=
|
6
|
-
<form method="POST" action="<%=u "/queues/#{
|
7
|
-
<input type='submit' name='' value='Remove Queue'
|
5
|
+
<h1>Pending jobs on <span class='hl'><%= h current_queue %></span></h1>
|
6
|
+
<form method="POST" action="<%=u "/queues/#{current_queue}/remove" %>" class='remove-queue'>
|
7
|
+
<input type='submit' name='' value='Remove Queue' class="confirmSubmission" />
|
8
8
|
</form>
|
9
|
-
<p class='sub'><%= page_entries_info start = params[:start].to_i, start + 19, size = resque.size(
|
9
|
+
<p class='sub'><%= page_entries_info start = params[:start].to_i, start + 19, size = resque.size(current_queue), 'job' %></p>
|
10
10
|
<table class='jobs'>
|
11
11
|
<tr>
|
12
12
|
<th>Class</th>
|
13
13
|
<th>Args</th>
|
14
14
|
</tr>
|
15
|
-
<% for job in (jobs = resque.peek(
|
15
|
+
<% for job in (jobs = resque.peek(current_queue, start, 20)) %>
|
16
16
|
<tr>
|
17
17
|
<td class='class'><%= partial :job_class, :job => job %></td>
|
18
18
|
<td class='args'><%=h job['args'].inspect %></td>
|
@@ -1,5 +1,5 @@
|
|
1
|
-
<% if params[:id] && (
|
2
|
-
<h1><%=
|
1
|
+
<% if params[:id] && (current_worker = Resque::Worker.find(params[:id])) && (data = current_worker.job) %>
|
2
|
+
<h1><%= current_worker %>'s job</h1>
|
3
3
|
|
4
4
|
<table>
|
5
5
|
<tr>
|
@@ -12,8 +12,8 @@
|
|
12
12
|
</tr>
|
13
13
|
<tr>
|
14
14
|
<td><img src="<%=u 'working.png' %>" alt="working" title="working"></td>
|
15
|
-
<% host, pid, _ =
|
16
|
-
<td><a href="<%=u "/workers/#{
|
15
|
+
<% host, pid, _ = current_worker.to_s.split(':') %>
|
16
|
+
<td><a href="<%=u "/workers/#{current_worker}" %>"><%= host %>:<%= pid %></a></td>
|
17
17
|
<% queue = data['queue'] %>
|
18
18
|
<td><a class="queue" href="<%=u "/queues/#{queue}" %>"><%= queue %></a></td>
|
19
19
|
<td><span class="time"><%= data['run_at'] %></span></td>
|
@@ -49,10 +49,10 @@
|
|
49
49
|
</tr>
|
50
50
|
<% end %>
|
51
51
|
|
52
|
-
<% worker_jobs.sort_by {|
|
52
|
+
<% worker_jobs.sort_by { |_w, j| j['run_at'] ? j['run_at'].to_s() : '' }.each do |worker, job| %>
|
53
53
|
<tr>
|
54
54
|
<td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
|
55
|
-
<% host, pid,
|
55
|
+
<% host, pid, _queues = worker.to_s.split(':') %>
|
56
56
|
<td class='where'><a href="<%=u "/workers/#{worker}" %>"><%= host %>:<%= pid %></a></td>
|
57
57
|
<td class='queues queue'>
|
58
58
|
<a class="queue-tag" href="<%=u "/queues/#{job['queue']}" %>"><%= job['queue'] %></a>
|
data/lib/resque/server.rb
CHANGED
@@ -5,7 +5,7 @@ require 'resque/version'
|
|
5
5
|
require 'time'
|
6
6
|
require 'yaml'
|
7
7
|
|
8
|
-
if defined? Encoding
|
8
|
+
if defined?(Encoding) && Encoding.default_external != Encoding::UTF_8
|
9
9
|
Encoding.default_external = Encoding::UTF_8
|
10
10
|
end
|
11
11
|
|
@@ -42,10 +42,6 @@ module Resque
|
|
42
42
|
end
|
43
43
|
alias_method :u, :url_path
|
44
44
|
|
45
|
-
def redirect_url_path(*path_parts)
|
46
|
-
[ path_prefix, path_parts ].join("/").squeeze('/')
|
47
|
-
end
|
48
|
-
|
49
45
|
def path_prefix
|
50
46
|
request.env['SCRIPT_NAME']
|
51
47
|
end
|
@@ -102,6 +98,8 @@ module Resque
|
|
102
98
|
Array(args).map do |a|
|
103
99
|
a.to_yaml
|
104
100
|
end.join("\n")
|
101
|
+
rescue
|
102
|
+
args.to_s
|
105
103
|
end
|
106
104
|
|
107
105
|
def worker_hosts
|
@@ -131,7 +129,7 @@ module Resque
|
|
131
129
|
end
|
132
130
|
|
133
131
|
def poll
|
134
|
-
if @polling
|
132
|
+
if defined?(@polling) && @polling
|
135
133
|
text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
|
136
134
|
else
|
137
135
|
text = "<a href='#{u(request.path_info)}.poll' rel='poll'>Live Poll</a>"
|
@@ -158,7 +156,7 @@ module Resque
|
|
158
156
|
|
159
157
|
# to make things easier on ourselves
|
160
158
|
get "/?" do
|
161
|
-
redirect
|
159
|
+
redirect url_path(:overview)
|
162
160
|
end
|
163
161
|
|
164
162
|
%w( overview workers ).each do |page|
|
@@ -207,6 +205,11 @@ module Resque
|
|
207
205
|
redirect u('failed')
|
208
206
|
end
|
209
207
|
|
208
|
+
post "/failed/clear_retried" do
|
209
|
+
Resque::Failure.clear_retried
|
210
|
+
redirect u('failed')
|
211
|
+
end
|
212
|
+
|
210
213
|
post "/failed/:queue/clear" do
|
211
214
|
Resque::Failure.clear params[:queue]
|
212
215
|
redirect u('failed')
|
@@ -219,7 +222,7 @@ module Resque
|
|
219
222
|
|
220
223
|
post "/failed/:queue/requeue/all" do
|
221
224
|
Resque::Failure.requeue_queue Resque::Failure.job_queue_name(params[:queue])
|
222
|
-
redirect
|
225
|
+
redirect url_path("/failed/#{params[:queue]}")
|
223
226
|
end
|
224
227
|
|
225
228
|
get "/failed/requeue/:index/?" do
|
@@ -251,7 +254,7 @@ module Resque
|
|
251
254
|
end
|
252
255
|
|
253
256
|
get "/stats/?" do
|
254
|
-
redirect
|
257
|
+
redirect url_path("/stats/resque")
|
255
258
|
end
|
256
259
|
|
257
260
|
get "/stats/:id/?" do
|
data/lib/resque/stat.rb
CHANGED
@@ -7,12 +7,19 @@ module Resque
|
|
7
7
|
# Kill a stat: Stat.clear(name)
|
8
8
|
module Stat
|
9
9
|
extend self
|
10
|
-
|
11
|
-
# Direct access to the Redis instance.
|
10
|
+
|
12
11
|
def redis
|
13
|
-
Resque
|
12
|
+
warn '[Resque] [Deprecation] Resque::Stat #redis method is deprecated (please use #data_strore)'
|
13
|
+
data_store
|
14
|
+
end
|
15
|
+
|
16
|
+
def data_store
|
17
|
+
@data_store ||= Resque.redis
|
18
|
+
end
|
19
|
+
|
20
|
+
def data_store=(data_store)
|
21
|
+
@data_store = data_store
|
14
22
|
end
|
15
|
-
alias :data_store :redis
|
16
23
|
|
17
24
|
# Returns the int value of a stat, given a string stat name.
|
18
25
|
def get(stat)
|
@@ -42,7 +49,7 @@ module Resque
|
|
42
49
|
# Can optionally accept a second int parameter. The stat is then
|
43
50
|
# decremented by that amount.
|
44
51
|
def decr(stat, by = 1)
|
45
|
-
data_store.
|
52
|
+
data_store.decrement_stat(stat,by)
|
46
53
|
end
|
47
54
|
|
48
55
|
# Decrements a stat by one.
|
data/lib/resque/tasks.rb
CHANGED
@@ -40,17 +40,9 @@ namespace :resque do
|
|
40
40
|
# Preload app files if this is Rails
|
41
41
|
task :preload => :setup do
|
42
42
|
if defined?(Rails)
|
43
|
-
if Rails
|
43
|
+
if Rails.application.config.eager_load
|
44
44
|
ActiveSupport.run_load_hooks(:before_eager_load, Rails.application)
|
45
45
|
Rails.application.config.eager_load_namespaces.each(&:eager_load!)
|
46
|
-
|
47
|
-
elsif Rails::VERSION::MAJOR == 3
|
48
|
-
ActiveSupport.run_load_hooks(:before_eager_load, Rails.application)
|
49
|
-
Rails.application.eager_load!
|
50
|
-
|
51
|
-
elsif defined?(Rails::Initializer)
|
52
|
-
$rails_rake_task = false
|
53
|
-
Rails::Initializer.run :load_application_classes
|
54
46
|
end
|
55
47
|
end
|
56
48
|
end
|
data/lib/resque/thread_signal.rb
CHANGED
@@ -1,45 +1,24 @@
|
|
1
1
|
class Resque::ThreadSignal
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
def initialize
|
3
|
+
@mutex = Mutex.new
|
4
|
+
@signaled = false
|
5
|
+
@received = ConditionVariable.new
|
6
|
+
end
|
6
7
|
|
7
|
-
|
8
|
+
def signal
|
9
|
+
@mutex.synchronize do
|
8
10
|
@signaled = true
|
11
|
+
@received.signal
|
9
12
|
end
|
13
|
+
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
+
def wait_for_signal(timeout)
|
16
|
+
@mutex.synchronize do
|
17
|
+
unless @signaled
|
18
|
+
@received.wait(@mutex, timeout)
|
15
19
|
end
|
16
20
|
|
17
21
|
@signaled
|
18
22
|
end
|
19
|
-
|
20
|
-
else
|
21
|
-
def initialize
|
22
|
-
@mutex = Mutex.new
|
23
|
-
@signaled = false
|
24
|
-
@received = ConditionVariable.new
|
25
|
-
end
|
26
|
-
|
27
|
-
def signal
|
28
|
-
@mutex.synchronize do
|
29
|
-
@signaled = true
|
30
|
-
@received.signal
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def wait_for_signal(timeout)
|
35
|
-
@mutex.synchronize do
|
36
|
-
unless @signaled
|
37
|
-
@received.wait(@mutex, timeout)
|
38
|
-
end
|
39
|
-
|
40
|
-
@signaled
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
23
|
end
|
45
24
|
end
|
@@ -7,7 +7,8 @@ module UTF8Util
|
|
7
7
|
#
|
8
8
|
# Returns self as valid UTF-8.
|
9
9
|
def self.clean!(str)
|
10
|
-
|
10
|
+
return str if str.encoding.to_s == "UTF-8"
|
11
|
+
str.force_encoding("binary").encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => REPLACEMENT_CHAR)
|
11
12
|
end
|
12
13
|
|
13
14
|
# Replace invalid UTF-8 character sequences with a replacement character
|
@@ -16,11 +17,4 @@ module UTF8Util
|
|
16
17
|
def self.clean(str)
|
17
18
|
clean!(str.dup)
|
18
19
|
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
if RUBY_VERSION <= '1.9'
|
23
|
-
require 'resque/vendor/utf8_util/utf8_util_18'
|
24
|
-
else
|
25
|
-
require 'resque/vendor/utf8_util/utf8_util_19'
|
26
20
|
end
|
data/lib/resque/version.rb
CHANGED
data/lib/resque/worker.rb
CHANGED
@@ -103,7 +103,7 @@ module Resque
|
|
103
103
|
skip_exists = options[:skip_exists]
|
104
104
|
|
105
105
|
if skip_exists || exists?(worker_id)
|
106
|
-
host, pid, queues_raw = worker_id.split(':')
|
106
|
+
host, pid, queues_raw = worker_id.split(':', 3)
|
107
107
|
queues = queues_raw.split(',')
|
108
108
|
worker = new(*queues)
|
109
109
|
worker.hostname = host
|
@@ -145,6 +145,11 @@ module Resque
|
|
145
145
|
@paused = nil
|
146
146
|
@before_first_fork_hook_ran = false
|
147
147
|
|
148
|
+
@heartbeat_thread = nil
|
149
|
+
@heartbeat_thread_signal = nil
|
150
|
+
|
151
|
+
@last_state = :idle
|
152
|
+
|
148
153
|
verbose_value = ENV['LOGGING'] || ENV['VERBOSE']
|
149
154
|
self.verbose = verbose_value if verbose_value
|
150
155
|
self.very_verbose = ENV['VVERBOSE'] if ENV['VVERBOSE']
|
@@ -162,9 +167,6 @@ module Resque
|
|
162
167
|
# once per worker.
|
163
168
|
def prepare
|
164
169
|
if ENV['BACKGROUND']
|
165
|
-
unless Process.respond_to?('daemon')
|
166
|
-
abort "env var BACKGROUND is set, which requires ruby >= 1.9"
|
167
|
-
end
|
168
170
|
Process.daemon(true)
|
169
171
|
end
|
170
172
|
|
@@ -175,12 +177,12 @@ module Resque
|
|
175
177
|
self.reconnect if ENV['BACKGROUND']
|
176
178
|
end
|
177
179
|
|
180
|
+
WILDCARDS = ['*', '?', '{', '}', '[', ']'].freeze
|
181
|
+
|
178
182
|
def queues=(queues)
|
179
183
|
queues = queues.empty? ? (ENV["QUEUES"] || ENV['QUEUE']).to_s.split(',') : queues
|
180
184
|
@queues = queues.map { |queue| queue.to_s.strip }
|
181
|
-
|
182
|
-
@static_queues = @queues.flatten.uniq
|
183
|
-
end
|
185
|
+
@has_dynamic_queues = WILDCARDS.any? {|char| @queues.join.include?(char) }
|
184
186
|
validate_queues
|
185
187
|
end
|
186
188
|
|
@@ -198,12 +200,16 @@ module Resque
|
|
198
200
|
# A splat ("*") means you want every queue (in alpha order) - this
|
199
201
|
# can be useful for dynamically adding new queues.
|
200
202
|
def queues
|
201
|
-
|
202
|
-
|
203
|
+
if @has_dynamic_queues
|
204
|
+
current_queues = Resque.queues
|
205
|
+
@queues.map { |queue| glob_match(current_queues, queue) }.flatten.uniq
|
206
|
+
else
|
207
|
+
@queues
|
208
|
+
end
|
203
209
|
end
|
204
210
|
|
205
|
-
def glob_match(pattern)
|
206
|
-
|
211
|
+
def glob_match(list, pattern)
|
212
|
+
list.select do |queue|
|
207
213
|
File.fnmatch?(pattern, queue)
|
208
214
|
end.sort
|
209
215
|
end
|
@@ -232,6 +238,7 @@ module Resque
|
|
232
238
|
break if shutdown?
|
233
239
|
|
234
240
|
unless work_one_job(&block)
|
241
|
+
state_change
|
235
242
|
break if interval.zero?
|
236
243
|
log_with_severity :debug, "Sleeping for #{interval} seconds"
|
237
244
|
procline paused? ? "Paused" : "Waiting for #{queues.join(',')}"
|
@@ -240,10 +247,12 @@ module Resque
|
|
240
247
|
end
|
241
248
|
|
242
249
|
unregister_worker
|
250
|
+
run_hook :worker_exit
|
243
251
|
rescue Exception => exception
|
244
252
|
return if exception.class == SystemExit && !@child && run_at_exit_hooks
|
245
253
|
log_with_severity :error, "Failed to start worker : #{exception.inspect}"
|
246
254
|
unregister_worker(exception)
|
255
|
+
run_hook :worker_exit
|
247
256
|
end
|
248
257
|
|
249
258
|
def work_one_job(job = nil, &block)
|
@@ -482,20 +491,22 @@ module Resque
|
|
482
491
|
# Returns a list of workers that have sent a heartbeat in the past, but which
|
483
492
|
# already expired (does NOT include workers that have never sent a heartbeat at all).
|
484
493
|
def self.all_workers_with_expired_heartbeats
|
485
|
-
|
494
|
+
# Use `Worker.all_heartbeats` instead of `Worker.all`
|
495
|
+
# to prune workers which haven't been registered but have set a heartbeat.
|
496
|
+
# https://github.com/resque/resque/pull/1751
|
486
497
|
heartbeats = Worker.all_heartbeats
|
487
498
|
now = data_store.server_time
|
488
499
|
|
489
|
-
|
490
|
-
id = worker.to_s
|
491
|
-
heartbeat = heartbeats[id]
|
492
|
-
|
500
|
+
heartbeats.select do |id, heartbeat|
|
493
501
|
if heartbeat
|
494
502
|
seconds_since_heartbeat = (now - Time.parse(heartbeat)).to_i
|
495
503
|
seconds_since_heartbeat > Resque.prune_interval
|
496
504
|
else
|
497
505
|
false
|
498
506
|
end
|
507
|
+
end.each_key.map do |id|
|
508
|
+
# skip_exists must be true to include not registered workers
|
509
|
+
find(id, :skip_exists => true)
|
499
510
|
end
|
500
511
|
end
|
501
512
|
|
@@ -588,23 +599,27 @@ module Resque
|
|
588
599
|
# By checking the current Redis state against the actual
|
589
600
|
# environment, we can determine if Redis is old and clean it up a bit.
|
590
601
|
def prune_dead_workers
|
591
|
-
|
602
|
+
return unless data_store.acquire_pruning_dead_worker_lock(self, Resque.heartbeat_interval)
|
592
603
|
|
593
|
-
|
594
|
-
known_workers = worker_pids
|
595
|
-
all_workers_with_expired_heartbeats = Worker.all_workers_with_expired_heartbeats
|
596
|
-
end
|
604
|
+
all_workers = Worker.all
|
597
605
|
|
598
|
-
|
606
|
+
known_workers = worker_pids
|
607
|
+
all_workers_with_expired_heartbeats = Worker.all_workers_with_expired_heartbeats
|
608
|
+
all_workers_with_expired_heartbeats.each do |worker|
|
599
609
|
# If the worker hasn't sent a heartbeat, remove it from the registry.
|
600
610
|
#
|
601
611
|
# If the worker hasn't ever sent a heartbeat, we won't remove it since
|
602
612
|
# the first heartbeat is sent before the worker is registred it means
|
603
613
|
# that this is a worker that doesn't support heartbeats, e.g., another
|
604
614
|
# client library or an older version of Resque. We won't touch these.
|
615
|
+
log_with_severity :info, "Pruning dead worker: #{worker}"
|
616
|
+
|
617
|
+
job_class = worker.job(false)['payload']['class'] rescue nil
|
618
|
+
worker.unregister_worker(PruneDeadWorkerDirtyExit.new(worker.to_s, job_class))
|
619
|
+
end
|
620
|
+
|
621
|
+
all_workers.each do |worker|
|
605
622
|
if all_workers_with_expired_heartbeats.include?(worker)
|
606
|
-
log_with_severity :info, "Pruning dead worker: #{worker}"
|
607
|
-
worker.unregister_worker(PruneDeadWorkerDirtyExit.new(worker.to_s))
|
608
623
|
next
|
609
624
|
end
|
610
625
|
|
@@ -635,7 +650,8 @@ module Resque
|
|
635
650
|
|
636
651
|
# Runs a named hook, passing along any arguments.
|
637
652
|
def run_hook(name, *args)
|
638
|
-
|
653
|
+
hooks = Resque.send(name)
|
654
|
+
return if hooks.empty?
|
639
655
|
return if name == :before_first_fork && @before_first_fork_hook_ran
|
640
656
|
msg = "Running #{name} hooks"
|
641
657
|
msg << " with #{args.inspect}" if args.any?
|
@@ -695,6 +711,7 @@ module Resque
|
|
695
711
|
:run_at => Time.now.utc.iso8601,
|
696
712
|
:payload => job.payload
|
697
713
|
data_store.set_worker_payload(self,data)
|
714
|
+
state_change
|
698
715
|
end
|
699
716
|
|
700
717
|
# Called when we are done working - clears our `working_on` state
|
@@ -705,6 +722,14 @@ module Resque
|
|
705
722
|
end
|
706
723
|
end
|
707
724
|
|
725
|
+
def state_change
|
726
|
+
current_state = state
|
727
|
+
if current_state != @last_state
|
728
|
+
run_hook :queue_empty if current_state == :idle
|
729
|
+
@last_state = current_state
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
708
733
|
# How many jobs has this worker processed? Returns an int.
|
709
734
|
def processed
|
710
735
|
Stat["processed:#{self}"]
|
@@ -808,7 +833,7 @@ module Resque
|
|
808
833
|
# machine. Useful when pruning dead workers on startup.
|
809
834
|
def windows_worker_pids
|
810
835
|
tasklist_output = `tasklist /FI "IMAGENAME eq ruby.exe" /FO list`.encode("UTF-8", Encoding.locale_charmap)
|
811
|
-
tasklist_output.split($/).select { |line| line =~ /^PID:/}.collect{ |line| line.gsub
|
836
|
+
tasklist_output.split($/).select { |line| line =~ /^PID:/ }.collect { |line| line.gsub(/PID:\s+/, '') }
|
812
837
|
end
|
813
838
|
|
814
839
|
# Find Resque worker pids on Linux and OS X.
|
@@ -827,7 +852,7 @@ module Resque
|
|
827
852
|
`ps -A -o pid,comm | grep "[r]uby" | grep -v "resque-web"`.split("\n").map do |line|
|
828
853
|
real_pid = line.split(' ')[0]
|
829
854
|
pargs_command = `pargs -a #{real_pid} 2>/dev/null | grep [r]esque | grep -v "resque-web"`
|
830
|
-
if pargs_command.split(':')[1] == " resque-#{Resque::
|
855
|
+
if pargs_command.split(':')[1] == " resque-#{Resque::VERSION}"
|
831
856
|
real_pid
|
832
857
|
end
|
833
858
|
end.compact
|
@@ -837,7 +862,7 @@ module Resque
|
|
837
862
|
# Procline is always in the format of:
|
838
863
|
# RESQUE_PROCLINE_PREFIXresque-VERSION: STRING
|
839
864
|
def procline(string)
|
840
|
-
$0 = "#{ENV['RESQUE_PROCLINE_PREFIX']}resque-#{Resque::
|
865
|
+
$0 = "#{ENV['RESQUE_PROCLINE_PREFIX']}resque-#{Resque::VERSION}: #{string}"
|
841
866
|
log_with_severity :debug, $0
|
842
867
|
end
|
843
868
|
|
@@ -850,13 +875,7 @@ module Resque
|
|
850
875
|
end
|
851
876
|
|
852
877
|
|
853
|
-
|
854
|
-
@verbose
|
855
|
-
end
|
856
|
-
|
857
|
-
def very_verbose
|
858
|
-
@very_verbose
|
859
|
-
end
|
878
|
+
attr_reader :verbose, :very_verbose
|
860
879
|
|
861
880
|
def verbose=(value);
|
862
881
|
if value && !very_verbose
|
@@ -909,7 +928,7 @@ module Resque
|
|
909
928
|
nil
|
910
929
|
end
|
911
930
|
|
912
|
-
job.fail(DirtyExit.new("Child process received unhandled signal #{
|
931
|
+
job.fail(DirtyExit.new("Child process received unhandled signal #{$?}", $?)) if $?.signaled?
|
913
932
|
@child = nil
|
914
933
|
end
|
915
934
|
|