resque 1.17.1 → 1.18.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.
- data/HISTORY.md +10 -0
- data/README.markdown +39 -10
- data/lib/resque.rb +8 -6
- data/lib/resque/failure/redis.rb +7 -2
- data/lib/resque/helpers.rb +13 -17
- data/lib/resque/plugin.rb +5 -0
- data/lib/resque/server.rb +4 -3
- data/lib/resque/tasks.rb +7 -0
- data/lib/resque/version.rb +1 -1
- data/lib/resque/worker.rb +30 -4
- data/test/job_hooks_test.rb +40 -0
- metadata +10 -18
data/HISTORY.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
## 1.18.0 (2011-08-18)
|
2
|
+
|
3
|
+
* Added before_enqueue hook.
|
4
|
+
* Resque workers now preload files under app/ in Rails
|
5
|
+
* Switch to MultiJSON
|
6
|
+
* Bugfix: Finding worker pids on Solaris
|
7
|
+
* Web UI: Fix NaN days ago for worker screens
|
8
|
+
* Web UI: Add Cache-Control header to prevent proxy caching
|
9
|
+
* Web UI: Update Resque.redis_id so it can be used in a distributed ring.
|
10
|
+
|
1
11
|
## 1.17.1 (2011-05-27)
|
2
12
|
|
3
13
|
* Reverted `exit` change. Back to `exit!`.
|
data/README.markdown
CHANGED
@@ -424,7 +424,7 @@ The Front End
|
|
424
424
|
Resque comes with a Sinatra-based front end for seeing what's up with
|
425
425
|
your queue.
|
426
426
|
|
427
|
-
![The Front End](
|
427
|
+
![The Front End](https://img.skitch.com/20110528-pc67a8qsfapgjxf5gagxd92fcu.png)
|
428
428
|
|
429
429
|
### Standalone
|
430
430
|
|
@@ -560,13 +560,8 @@ together. But, it's not that hard.
|
|
560
560
|
Resque Dependencies
|
561
561
|
-------------------
|
562
562
|
|
563
|
-
gem install
|
564
|
-
|
565
|
-
If you cannot install `yajl-ruby` (JRuby?), you can install the `json`
|
566
|
-
gem and Resque will use it instead.
|
567
|
-
|
568
|
-
When problems arise, make sure you have the newest versions of the
|
569
|
-
`redis` and `redis-namespace` gems.
|
563
|
+
$ gem install bundler
|
564
|
+
$ bundle install
|
570
565
|
|
571
566
|
|
572
567
|
Installing Resque
|
@@ -606,7 +601,7 @@ Alternately you can define a `resque:setup` hook in your Rakefile if you
|
|
606
601
|
don't want to load your app every time rake runs.
|
607
602
|
|
608
603
|
|
609
|
-
### In a Rails app, as a gem
|
604
|
+
### In a Rails 2.x app, as a gem
|
610
605
|
|
611
606
|
First install the gem.
|
612
607
|
|
@@ -637,7 +632,7 @@ Don't forget you can define a `resque:setup` hook in
|
|
637
632
|
`lib/tasks/whatever.rake` that loads the `environment` task every time.
|
638
633
|
|
639
634
|
|
640
|
-
### In a Rails app, as a plugin
|
635
|
+
### In a Rails 2.x app, as a plugin
|
641
636
|
|
642
637
|
$ ./script/plugin install git://github.com/defunkt/resque
|
643
638
|
|
@@ -652,6 +647,40 @@ Don't forget you can define a `resque:setup` hook in
|
|
652
647
|
`lib/tasks/whatever.rake` that loads the `environment` task every time.
|
653
648
|
|
654
649
|
|
650
|
+
### In a Rails 3 app, as a gem
|
651
|
+
|
652
|
+
First include it in your Gemfile.
|
653
|
+
|
654
|
+
$ cat Gemfile
|
655
|
+
...
|
656
|
+
gem 'resque'
|
657
|
+
...
|
658
|
+
|
659
|
+
Next install it with Bundler.
|
660
|
+
|
661
|
+
$ bundle install
|
662
|
+
|
663
|
+
Now start your application:
|
664
|
+
|
665
|
+
$ rails server
|
666
|
+
|
667
|
+
That's it! You can now create Resque jobs from within your app.
|
668
|
+
|
669
|
+
To start a worker, add this to a file in `lib/tasks` (ex:
|
670
|
+
`lib/tasks/resque.rake`):
|
671
|
+
|
672
|
+
``` ruby
|
673
|
+
require 'resque/tasks'
|
674
|
+
```
|
675
|
+
|
676
|
+
Now:
|
677
|
+
|
678
|
+
$ QUEUE=* rake environment resque:work
|
679
|
+
|
680
|
+
Don't forget you can define a `resque:setup` hook in
|
681
|
+
`lib/tasks/whatever.rake` that loads the `environment` task every time.
|
682
|
+
|
683
|
+
|
655
684
|
Configuration
|
656
685
|
-------------
|
657
686
|
|
data/lib/resque.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
require 'redis/namespace'
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'yajl'
|
5
|
-
rescue LoadError
|
6
|
-
require 'json'
|
7
|
-
end
|
8
|
-
|
9
3
|
require 'resque/version'
|
10
4
|
|
11
5
|
require 'resque/errors'
|
@@ -63,6 +57,8 @@ module Resque
|
|
63
57
|
# support 1.x versions of redis-rb
|
64
58
|
if redis.respond_to?(:server)
|
65
59
|
redis.server
|
60
|
+
elsif redis.respond_to?(:nodes) # distributed
|
61
|
+
redis.nodes.map { |n| n.id }.join(', ')
|
66
62
|
else
|
67
63
|
redis.client.id
|
68
64
|
end
|
@@ -228,6 +224,12 @@ module Resque
|
|
228
224
|
#
|
229
225
|
# This method is considered part of the `stable` API.
|
230
226
|
def enqueue(klass, *args)
|
227
|
+
# Perform before_enqueue hooks. Don't perform enqueue if any hook returns false
|
228
|
+
before_hooks = Plugin.before_enqueue_hooks(klass).collect do |hook|
|
229
|
+
klass.send(hook, *args)
|
230
|
+
end
|
231
|
+
return if before_hooks.any? { |result| result == false }
|
232
|
+
|
231
233
|
Job.create(queue_from_class(klass), klass, *args)
|
232
234
|
|
233
235
|
Plugin.after_enqueue_hooks(klass).each do |hook|
|
data/lib/resque/failure/redis.rb
CHANGED
@@ -5,11 +5,11 @@ module Resque
|
|
5
5
|
class Redis < Base
|
6
6
|
def save
|
7
7
|
data = {
|
8
|
-
:failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S"),
|
8
|
+
:failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
|
9
9
|
:payload => payload,
|
10
10
|
:exception => exception.class.to_s,
|
11
11
|
:error => exception.to_s,
|
12
|
-
:backtrace => Array(exception.backtrace),
|
12
|
+
:backtrace => filter_backtrace(Array(exception.backtrace)),
|
13
13
|
:worker => worker.to_s,
|
14
14
|
:queue => queue
|
15
15
|
}
|
@@ -41,6 +41,11 @@ module Resque
|
|
41
41
|
Resque.redis.lset(:failed, index, id)
|
42
42
|
Resque.redis.lrem(:failed, 1, id)
|
43
43
|
end
|
44
|
+
|
45
|
+
def filter_backtrace(backtrace)
|
46
|
+
index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
|
47
|
+
backtrace.first(index.to_i)
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
end
|
data/lib/resque/helpers.rb
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
|
3
|
+
# OkJson won't work because it doesn't serialize symbols
|
4
|
+
# in the same way yajl and json do.
|
5
|
+
if MultiJson.engine.to_s == 'MultiJson::Engines::OkJson'
|
6
|
+
raise "Please install the yajl-ruby or json gem"
|
7
|
+
end
|
8
|
+
|
1
9
|
module Resque
|
2
10
|
# Methods used by various classes in Resque.
|
3
11
|
module Helpers
|
@@ -11,29 +19,17 @@ module Resque
|
|
11
19
|
# Given a Ruby object, returns a string suitable for storage in a
|
12
20
|
# queue.
|
13
21
|
def encode(object)
|
14
|
-
|
15
|
-
Yajl::Encoder.encode(object)
|
16
|
-
else
|
17
|
-
object.to_json
|
18
|
-
end
|
22
|
+
::MultiJson.encode(object)
|
19
23
|
end
|
20
24
|
|
21
25
|
# Given a string, returns a Ruby object.
|
22
26
|
def decode(object)
|
23
27
|
return unless object
|
24
28
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
raise DecodeException, e
|
30
|
-
end
|
31
|
-
else
|
32
|
-
begin
|
33
|
-
JSON.parse(object)
|
34
|
-
rescue JSON::ParserError => e
|
35
|
-
raise DecodeException, e
|
36
|
-
end
|
29
|
+
begin
|
30
|
+
::MultiJson.decode(object)
|
31
|
+
rescue ::MultiJson::DecodeError => e
|
32
|
+
raise DecodeException, e
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
data/lib/resque/plugin.rb
CHANGED
@@ -47,5 +47,10 @@ module Resque
|
|
47
47
|
def after_enqueue_hooks(job)
|
48
48
|
job.methods.grep(/^after_enqueue/).sort
|
49
49
|
end
|
50
|
+
|
51
|
+
# Given an object, returns a list `before_enqueue` hook names.
|
52
|
+
def before_enqueue_hooks(job)
|
53
|
+
job.methods.grep(/^before_enqueue/).sort
|
54
|
+
end
|
50
55
|
end
|
51
56
|
end
|
data/lib/resque/server.rb
CHANGED
@@ -119,13 +119,14 @@ module Resque
|
|
119
119
|
end
|
120
120
|
|
121
121
|
def show(page, layout = true)
|
122
|
+
response["Cache-Control"] = "max-age=0, private, must-revalidate"
|
122
123
|
begin
|
123
124
|
erb page.to_sym, {:layout => layout}, :resque => Resque
|
124
125
|
rescue Errno::ECONNREFUSED
|
125
126
|
erb :error, {:layout => false}, :error => "Can't connect to Redis! (#{Resque.redis_id})"
|
126
127
|
end
|
127
128
|
end
|
128
|
-
|
129
|
+
|
129
130
|
def show_for_polling(page)
|
130
131
|
content_type "text/html"
|
131
132
|
@polling = true
|
@@ -136,12 +137,12 @@ module Resque
|
|
136
137
|
get "/?" do
|
137
138
|
redirect url_path(:overview)
|
138
139
|
end
|
139
|
-
|
140
|
+
|
140
141
|
%w( overview workers ).each do |page|
|
141
142
|
get "/#{page}.poll" do
|
142
143
|
show_for_polling(page)
|
143
144
|
end
|
144
|
-
|
145
|
+
|
145
146
|
get "/#{page}/:id.poll" do
|
146
147
|
show_for_polling(page)
|
147
148
|
end
|
data/lib/resque/tasks.rb
CHANGED
data/lib/resque/version.rb
CHANGED
data/lib/resque/worker.rb
CHANGED
@@ -36,7 +36,7 @@ module Resque
|
|
36
36
|
names.map! { |name| "worker:#{name}" }
|
37
37
|
|
38
38
|
reportedly_working = redis.mapped_mget(*names).reject do |key, value|
|
39
|
-
value.nil?
|
39
|
+
value.nil? || value.empty?
|
40
40
|
end
|
41
41
|
reportedly_working.keys.map do |key|
|
42
42
|
find key.sub("worker:", '')
|
@@ -302,7 +302,7 @@ module Resque
|
|
302
302
|
def paused?
|
303
303
|
@paused
|
304
304
|
end
|
305
|
-
|
305
|
+
|
306
306
|
# Stop processing jobs after the current one has completed (if we're
|
307
307
|
# currently running one).
|
308
308
|
def pause_processing
|
@@ -381,7 +381,7 @@ module Resque
|
|
381
381
|
job.worker = self
|
382
382
|
data = encode \
|
383
383
|
:queue => job.queue,
|
384
|
-
:run_at => Time.now.
|
384
|
+
:run_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
|
385
385
|
:payload => job.payload
|
386
386
|
redis.set("worker:#{self}", data)
|
387
387
|
end
|
@@ -473,14 +473,40 @@ module Resque
|
|
473
473
|
@pid ||= to_s.split(":")[1].to_i
|
474
474
|
end
|
475
475
|
|
476
|
-
# Returns an
|
476
|
+
# Returns an Array of string pids of all the other workers on this
|
477
477
|
# machine. Useful when pruning dead workers on startup.
|
478
478
|
def worker_pids
|
479
|
+
if RUBY_PLATFORM =~ /solaris/
|
480
|
+
solaris_worker_pids
|
481
|
+
else
|
482
|
+
linux_worker_pids
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
# Find Resque worker pids on Linux and OS X.
|
487
|
+
#
|
488
|
+
# Returns an Array of string pids of all the other workers on this
|
489
|
+
# machine. Useful when pruning dead workers on startup.
|
490
|
+
def linux_worker_pids
|
479
491
|
`ps -A -o pid,command | grep [r]esque | grep -v "resque-web"`.split("\n").map do |line|
|
480
492
|
line.split(' ')[0]
|
481
493
|
end
|
482
494
|
end
|
483
495
|
|
496
|
+
# Find Resque worker pids on Solaris.
|
497
|
+
#
|
498
|
+
# Returns an Array of string pids of all the other workers on this
|
499
|
+
# machine. Useful when pruning dead workers on startup.
|
500
|
+
def solaris_worker_pids
|
501
|
+
`ps -A -o pid,comm | grep ruby | grep -v grep | grep -v "resque-web"`.split("\n").map do |line|
|
502
|
+
real_pid = line.split(' ')[0]
|
503
|
+
pargs_command = `pargs -a #{real_pid} 2>/dev/null | grep [r]esque | grep -v "resque-web"`
|
504
|
+
if pargs_command.split(':')[1] == " resque-#{Resque::Version}"
|
505
|
+
real_pid
|
506
|
+
end
|
507
|
+
end.compact
|
508
|
+
end
|
509
|
+
|
484
510
|
# Given a string, sets the procline ($0) and logs.
|
485
511
|
# Procline is always in the format of:
|
486
512
|
# resque-VERSION: STRING
|
data/test/job_hooks_test.rb
CHANGED
@@ -250,6 +250,46 @@ context "Resque::Job after_enqueue" do
|
|
250
250
|
end
|
251
251
|
end
|
252
252
|
|
253
|
+
|
254
|
+
context "Resque::Job before_enqueue" do
|
255
|
+
include PerformJob
|
256
|
+
|
257
|
+
class ::BeforeEnqueueJob
|
258
|
+
@queue = :jobs
|
259
|
+
def self.before_enqueue_record_history(history)
|
260
|
+
history << :before_enqueue
|
261
|
+
end
|
262
|
+
|
263
|
+
def self.perform(history)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class ::BeforeEnqueueJobAbort
|
268
|
+
@queue = :jobs
|
269
|
+
def self.before_enqueue_abort(history)
|
270
|
+
false
|
271
|
+
end
|
272
|
+
|
273
|
+
def self.perform(history)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
test "the before enqueue hook should run" do
|
278
|
+
history = []
|
279
|
+
@worker = Resque::Worker.new(:jobs)
|
280
|
+
Resque.enqueue(BeforeEnqueueJob, history)
|
281
|
+
@worker.work(0)
|
282
|
+
assert_equal history, [:before_enqueue], "before_enqueue was not run"
|
283
|
+
end
|
284
|
+
|
285
|
+
test "a before enqueue hook that returns false should prevent the job from getting queued" do
|
286
|
+
history = []
|
287
|
+
@worker = Resque::Worker.new(:jobs)
|
288
|
+
Resque.enqueue(BeforeEnqueueJobAbort, history)
|
289
|
+
assert_equal 0, Resque.size(:jobs)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
253
293
|
context "Resque::Job all hooks" do
|
254
294
|
include PerformJob
|
255
295
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: resque
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 95
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 18
|
9
|
+
- 0
|
10
|
+
version: 1.18.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chris Wanstrath
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-18 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -67,26 +67,18 @@ dependencies:
|
|
67
67
|
type: :runtime
|
68
68
|
version_requirements: *id003
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: multi_json
|
71
71
|
prerelease: false
|
72
72
|
requirement: &id004 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
hash: 11
|
78
|
-
segments:
|
79
|
-
- 1
|
80
|
-
- 4
|
81
|
-
- 6
|
82
|
-
version: 1.4.6
|
83
|
-
- - <
|
75
|
+
- - ~>
|
84
76
|
- !ruby/object:Gem::Version
|
85
|
-
hash:
|
77
|
+
hash: 15
|
86
78
|
segments:
|
87
79
|
- 1
|
88
|
-
-
|
89
|
-
version: "1.
|
80
|
+
- 0
|
81
|
+
version: "1.0"
|
90
82
|
type: :runtime
|
91
83
|
version_requirements: *id004
|
92
84
|
description: " Resque is a Redis-backed Ruby library for creating background jobs,\n placing those jobs on multiple queues, and processing them later.\n\n Background jobs can be any Ruby class or module that responds to\n perform. Your existing classes can easily be converted to background\n jobs or you can create new classes specifically to do work. Or, you\n can do both.\n\n Resque is heavily inspired by DelayedJob (which rocks) and is\n comprised of three parts:\n\n * A Ruby library for creating, querying, and processing jobs\n * A Rake task for starting a worker which processes jobs\n * A Sinatra app for monitoring queues, jobs, and workers.\n"
|