Skip to content

Commit 7b2f561

Browse files
committed
Merge branch 'master' into 2.0
Conflicts: HISTORY.md test/worker_test.rb
2 parents 408b7e8 + eb6faa3 commit 7b2f561

19 files changed

+1078
-58
lines changed

HISTORY.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
* Resque now uses Unix Epoch Timestamps exclusively.
44

5+
## 1.7.1 (2010-04-02)
6+
7+
* Bugfix: Make job hook execution order consistent
8+
* Bugfix: stdout buffering in child process
9+
10+
## 1.7.0 (2010-03-31)
11+
12+
* Job hooks API. See docs/HOOKS.md.
13+
* web: Hovering over dates shows a timestamp
14+
* web: AJAXify retry action for failed jobs
15+
* web bugfix: Fix pagination bug
16+
>>>>>>> master
17+
518
## 1.6.1 (2010-03-25)
619

720
* Bugfix: Workers may not be clearing their state correctly on

README.markdown

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -653,39 +653,16 @@ this way we can tell our Sinatra app about the config file:
653653

654654
Now everyone is on the same page.
655655

656-
Worker Hooks
657-
------------
658-
659-
If you wish to have a Proc called before the worker forks for the
660-
first time, you can add it in the initializer like so:
661-
662-
Resque.before_first_fork do
663-
puts "Call me once before the worker forks the first time"
664-
end
665-
666-
You can also run a hook before _every_ fork:
667-
668-
Resque.before_fork do |job|
669-
puts "Call me before the worker forks"
670-
end
671-
672-
The `before_fork` hook will be run in the **parent** process. So, be
673-
careful - any changes you make will be permanent for the lifespan of
674-
the worker.
675-
676-
And after forking:
677656

678-
Resque.after_fork do |job|
679-
puts "Call me after the worker forks"
680-
end
681-
682-
The `after_fork` hook will be run in the child process and is passed
683-
the current job. Any changes you make, therefor, will only live as
684-
long as the job currently being processes.
657+
Plugins and Hooks
658+
-----------------
685659

686-
All hooks can also be set using a setter, e.g.
660+
For a list of available plugins see
661+
<http://wiki.github.com/defunkt/resque/plugins>.
687662

688-
Resque.after_fork = proc { puts "called" }
663+
If you'd like to write your own plugin, or want to customize Resque
664+
using hooks (such as `Resque.after_fork`), see
665+
[docs/HOOKS.md](http://github.com/defunkt/resque/blob/master/HOOKS.md).
689666

690667
To clear all hooks, set nil or false:
691668

@@ -788,7 +765,7 @@ Mailing List
788765

789766
To join the list simply send an email to <[email protected]>. This
790767
will subscribe you and send you information about your subscription,
791-
include unsubscribe information.
768+
including unsubscribe information.
792769

793770
The archive can be found at <http://librelist.com/browser/>.
794771

Rakefile

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,45 @@
1+
#
2+
# Setup
3+
#
4+
15
load 'tasks/redis.rake'
6+
require 'rake/testtask'
27

38
$LOAD_PATH.unshift 'lib'
49
require 'resque/tasks'
510

11+
def command?(command)
12+
system("type #{command} > /dev/null")
13+
end
14+
15+
16+
#
17+
# Tests
18+
#
19+
620
task :default => :test
721

8-
desc "Run tests"
22+
desc "Run the test suite"
923
task :test do
10-
# Don't use the rake/testtask because it loads a new
11-
# Ruby interpreter - we want to run tests with the current
12-
# `rake` so our library manager still works
13-
Dir['test/*_test.rb'].each do |f|
14-
require f
24+
rg = command?(:rg)
25+
Dir['test/**/*_test.rb'].each do |f|
26+
rg ? sh("rg #{f}") : ruby(f)
1527
end
1628
end
1729

18-
desc "Activate kicker - gem install kicker"
19-
task :kick do
20-
exec "kicker -e rake lib test"
30+
if command? :kicker
31+
desc "Launch Kicker (like autotest)"
32+
task :kicker do
33+
puts "Kicking... (ctrl+c to cancel)"
34+
exec "kicker -e rake test lib examples"
35+
end
2136
end
2237

38+
39+
#
40+
# Gem
41+
#
42+
2343
task :install => [ 'redis:install', 'dtach:install' ]
2444

2545
desc "Build a gem"
@@ -31,8 +51,7 @@ begin
3151

3252
Jeweler::Tasks.new do |gemspec|
3353
gemspec.name = "resque"
34-
gemspec.summary = ""
35-
gemspec.description = ""
54+
gemspec.summary = "Resque is a Redis-backed queueing system."
3655
gemspec.email = "[email protected]"
3756
gemspec.homepage = "http://github.com/defunkt/resque"
3857
gemspec.authors = ["Chris Wanstrath"]
@@ -43,18 +62,45 @@ begin
4362
gemspec.add_dependency "vegas", ">=0.1.2"
4463
gemspec.add_dependency "sinatra", ">=0.9.2"
4564
gemspec.add_development_dependency "jeweler"
65+
66+
gemspec.description = <<description
67+
Resque is a Redis-backed Ruby library for creating background jobs,
68+
placing those jobs on multiple queues, and processing them later.
69+
70+
Background jobs can be any Ruby class or module that responds to
71+
perform. Your existing classes can easily be converted to background
72+
jobs or you can create new classes specifically to do work. Or, you
73+
can do both.
74+
75+
Resque is heavily inspired by DelayedJob (which rocks) and is
76+
comprised of three parts:
77+
78+
* A Ruby library for creating, querying, and processing jobs
79+
* A Rake task for starting a worker which processes jobs
80+
* A Sinatra app for monitoring queues, jobs, and workers.
81+
description
4682
end
4783
rescue LoadError
4884
puts "Jeweler not available. Install it with: "
4985
puts "gem install jeweler"
5086
end
5187

88+
89+
#
90+
# Documentation
91+
#
92+
5293
begin
5394
require 'sdoc_helpers'
5495
rescue LoadError
5596
puts "sdoc support not enabled. Please gem install sdoc-helpers."
5697
end
5798

99+
100+
#
101+
# Publishing
102+
#
103+
58104
desc "Push a new version to Gemcutter"
59105
task :publish => [ :test, :gemspec, :build ] do
60106
system "git tag v#{Resque::Version}"

docs/HOOKS.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
Resque Hooks
2+
============
3+
4+
You can customize Resque or write plugins using its hook API. In many
5+
cases you can use a hook rather than mess with Resque's internals.
6+
7+
For a list of available plugins see
8+
<http://wiki.github.com/defunkt/resque/plugins>.
9+
10+
11+
Worker Hooks
12+
------------
13+
14+
If you wish to have a Proc called before the worker forks for the
15+
first time, you can add it in the initializer like so:
16+
17+
Resque.before_first_fork do
18+
puts "Call me once before the worker forks the first time"
19+
end
20+
21+
You can also run a hook before _every_ fork:
22+
23+
Resque.before_fork do |job|
24+
puts "Call me before the worker forks"
25+
end
26+
27+
The `before_fork` hook will be run in the **parent** process. So, be
28+
careful - any changes you make will be permanent for the lifespan of
29+
the worker.
30+
31+
And after forking:
32+
33+
Resque.after_fork do |job|
34+
puts "Call me after the worker forks"
35+
end
36+
37+
The `after_fork` hook will be run in the child process and is passed
38+
the current job. Any changes you make, therefor, will only live as
39+
long as the job currently being processes.
40+
41+
All worker hooks can also be set using a setter, e.g.
42+
43+
Resque.after_fork = proc { puts "called" }
44+
45+
46+
Job Hooks
47+
---------
48+
49+
Plugins can utilize job hooks to provide additional behavior. A job
50+
hook is a method name in the following format:
51+
52+
HOOKNAME_IDENTIFIER
53+
54+
For example, a `before_perform` hook which adds locking may be defined
55+
like this:
56+
57+
def before_perform_with_lock(*args)
58+
set_lock!
59+
end
60+
61+
Once this hook is made available to your job (either by way of
62+
inheritence or `extend`), it will be run before the job's `perform`
63+
method is called. Hooks of each type are executed in alphabetical order,
64+
so `before_perform_a` will always be executed before `before_perform_b`.
65+
An unnamed hook (`before_perform`) will be executed first.
66+
67+
The available hooks are:
68+
69+
* `before_perform`: Called with the job args before perform. If it raises
70+
`Resque::Job::DontPerform`, the job is aborted. If other exceptions
71+
are raised, they will be propagated up the the `Resque::Failure`
72+
backend.
73+
74+
* `after_perform`: Called with the job args after it performs. Uncaught
75+
exceptions will propagate up to the `Resque::Failure` backend.
76+
77+
* `around_perform`: Called with the job args. It is expected to yield in order
78+
to perform the job (but is not required to do so). It may handle exceptions
79+
thrown by `perform`, but any that are not caught will propagate up to the
80+
`Resque::Failure` backend.
81+
82+
* `on_failure`: Called with the exception and job args if any exception occurs
83+
while performing the job (or hooks).
84+
85+
Hooks are easily implemented with superclasses or modules. A superclass could
86+
look something like this.
87+
88+
class LoggedJob
89+
def self.before_perform_log_job(*args)
90+
Logger.info "About to perform #{self} with #{args.inspect}"
91+
end
92+
end
93+
94+
class MyJob < LoggedJob
95+
def self.perform(*args)
96+
...
97+
end
98+
end
99+
100+
Modules are even better because jobs can use many of them.
101+
102+
module LoggedJob
103+
def before_perform_log_job(*args)
104+
Logger.info "About to perform #{self} with #{args.inspect}"
105+
end
106+
end
107+
108+
module RetriedJob
109+
def on_failure_retry(e, *args)
110+
Logger.info "Performing #{self} caused an exception (#{e}). Retrying..."
111+
Resque.enqueue self, *args
112+
end
113+
end
114+
115+
class MyJob
116+
extend LoggedJob
117+
extend RetriedJob
118+
def self.perform(*args)
119+
...
120+
end
121+
end

0 commit comments

Comments
 (0)