Skip to content

Commit

Permalink
Merge branch 'defunkt' into distributed
Browse files Browse the repository at this point in the history
Conflicts:
	lib/resque/worker.rb
  • Loading branch information
mpd committed Jul 18, 2011
2 parents d68e999 + d85097d commit 9016204
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 36 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -7,4 +7,6 @@ group :test do
gem "rack-test", "~> 0.5"
gem "mocha", "~> 0.9.7"
gem "leftright", :platforms => :mri_18
gem "yajl-ruby", "~>0.8.2", :platforms => :mri
gem "json", "~>1.5.3", :platforms => :jruby
end
47 changes: 38 additions & 9 deletions README.markdown
Expand Up @@ -560,13 +560,8 @@ together. But, it's not that hard.
Resque Dependencies
-------------------

gem install redis redis-namespace yajl-ruby vegas sinatra

If you cannot install `yajl-ruby` (JRuby?), you can install the `json`
gem and Resque will use it instead.

When problems arise, make sure you have the newest versions of the
`redis` and `redis-namespace` gems.
$ gem install bundler
$ bundle install


Installing Resque
Expand Down Expand Up @@ -606,7 +601,7 @@ Alternately you can define a `resque:setup` hook in your Rakefile if you
don't want to load your app every time rake runs.


### In a Rails app, as a gem
### In a Rails 2.x app, as a gem

First install the gem.

Expand Down Expand Up @@ -637,7 +632,7 @@ Don't forget you can define a `resque:setup` hook in
`lib/tasks/whatever.rake` that loads the `environment` task every time.


### In a Rails app, as a plugin
### In a Rails 2.x app, as a plugin

$ ./script/plugin install git://github.com/defunkt/resque

Expand All @@ -652,6 +647,40 @@ Don't forget you can define a `resque:setup` hook in
`lib/tasks/whatever.rake` that loads the `environment` task every time.


### In a Rails 3 app, as a gem

First include it in your Gemfile.

$ cat Gemfile
...
gem 'resque'
...

Next install it with Bundler.

$ bundle install

Now start your application:

$ rails server

That's it! You can now create Resque jobs from within your app.

To start a worker, add this to a file in `lib/tasks` (ex:
`lib/tasks/resque.rake`):

``` ruby
require 'resque/tasks'
```

Now:

$ QUEUE=* rake environment resque:work

Don't forget you can define a `resque:setup` hook in
`lib/tasks/whatever.rake` that loads the `environment` task every time.


Configuration
-------------

Expand Down
3 changes: 3 additions & 0 deletions docs/HOOKS.md
Expand Up @@ -66,6 +66,9 @@ An unnamed hook (`before_perform`) will be executed first.

The available hooks are:

* `before _enqueue`: Called with the job args before a job is placed on the queue.
If the hook returns `false`, the job will not be placed on the queue.

* `after_enqueue`: Called with the job args after a job is placed on the queue.
Any exception raised propagates up to the code which queued the job.

Expand Down
1 change: 1 addition & 0 deletions examples/god/resque.god
Expand Up @@ -4,6 +4,7 @@ num_workers = rails_env == 'production' ? 5 : 2

num_workers.times do |num|
God.watch do |w|
w.dir = "#{rails_root}"
w.name = "resque-#{num}"
w.group = 'resque'
w.interval = 30.seconds
Expand Down
12 changes: 6 additions & 6 deletions lib/resque.rb
@@ -1,11 +1,5 @@
require 'redis/namespace'

begin
require 'yajl'
rescue LoadError
require 'json'
end

require 'resque/version'

require 'resque/errors'
Expand Down Expand Up @@ -230,6 +224,12 @@ def watch_queue(queue)
#
# This method is considered part of the `stable` API.
def enqueue(klass, *args)
# Perform before_enqueue hooks. Don't perform enqueue if any hook returns false
before_hooks = Plugin.before_enqueue_hooks(klass).collect do |hook|
klass.send(hook, *args)
end
return if before_hooks.any? { |result| result == false }

Job.create(queue_from_class(klass), klass, *args)

Plugin.after_enqueue_hooks(klass).each do |hook|
Expand Down
7 changes: 6 additions & 1 deletion lib/resque/failure/redis.rb
Expand Up @@ -9,7 +9,7 @@ def save
:payload => payload,
:exception => exception.class.to_s,
:error => exception.to_s,
:backtrace => Array(exception.backtrace),
:backtrace => filter_backtrace(Array(exception.backtrace)),
:worker => worker.to_s,
:queue => queue
}
Expand Down Expand Up @@ -41,6 +41,11 @@ def self.remove(index)
Resque.redis.lset(:failed, index, id)
Resque.redis.lrem(:failed, 1, id)
end

def filter_backtrace(backtrace)
index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
backtrace.first(index.to_i)
end
end
end
end
30 changes: 13 additions & 17 deletions lib/resque/helpers.rb
@@ -1,3 +1,11 @@
require 'multi_json'

# OkJson won't work because it doesn't serialize symbols
# in the same way yajl and json do.
if MultiJson.engine.to_s == 'MultiJson::Engines::OkJson'
raise "Please install the yajl-ruby or json gem"
end

module Resque
# Methods used by various classes in Resque.
module Helpers
Expand All @@ -11,29 +19,17 @@ def redis
# Given a Ruby object, returns a string suitable for storage in a
# queue.
def encode(object)
if defined? Yajl
Yajl::Encoder.encode(object)
else
object.to_json
end
::MultiJson.encode(object)
end

# Given a string, returns a Ruby object.
def decode(object)
return unless object

if defined? Yajl
begin
Yajl::Parser.parse(object, :check_utf8 => false)
rescue Yajl::ParseError => e
raise DecodeException, e
end
else
begin
JSON.parse(object)
rescue JSON::ParserError => e
raise DecodeException, e
end
begin
::MultiJson.decode(object)
rescue ::MultiJson::DecodeError => e
raise DecodeException, e
end
end

Expand Down
5 changes: 5 additions & 0 deletions lib/resque/plugin.rb
Expand Up @@ -47,5 +47,10 @@ def failure_hooks(job)
def after_enqueue_hooks(job)
job.methods.grep(/^after_enqueue/).sort
end

# Given an object, returns a list `before_enqueue` hook names.
def before_enqueue_hooks(job)
job.methods.grep(/^before_enqueue/).sort
end
end
end
4 changes: 2 additions & 2 deletions lib/resque/worker.rb
Expand Up @@ -37,13 +37,13 @@ def self.working

reportedly_working = begin
redis.mapped_mget(*names).reject do |key, value|
value.nil?
value.nil? || value.empty?
end
rescue Redis::Distributed::CannotDistribute
result = {}
names.each do |name|
value = redis.get name
result[name] = value unless value.nil?
result[name] = value unless value.nil? || value.empty?
end
result
end
Expand Down
2 changes: 1 addition & 1 deletion resque.gemspec
Expand Up @@ -24,7 +24,7 @@ Gem::Specification.new do |s|
s.add_dependency "redis-namespace", "~> 1.0.2"
s.add_dependency "vegas", "~> 0.1.2"
s.add_dependency "sinatra", ">= 0.9.2"
s.add_dependency "json", ">= 1.4.6", "< 1.6"
s.add_dependency "multi_json", "~> 1.0"

s.description = <<description
Resque is a Redis-backed Ruby library for creating background jobs,
Expand Down
40 changes: 40 additions & 0 deletions test/job_hooks_test.rb
Expand Up @@ -250,6 +250,46 @@ def self.perform(history)
end
end


context "Resque::Job before_enqueue" do
include PerformJob

class ::BeforeEnqueueJob
@queue = :jobs
def self.before_enqueue_record_history(history)
history << :before_enqueue
end

def self.perform(history)
end
end

class ::BeforeEnqueueJobAbort
@queue = :jobs
def self.before_enqueue_abort(history)
false
end

def self.perform(history)
end
end

test "the before enqueue hook should run" do
history = []
@worker = Resque::Worker.new(:jobs)
Resque.enqueue(BeforeEnqueueJob, history)
@worker.work(0)
assert_equal history, [:before_enqueue], "before_enqueue was not run"
end

test "a before enqueue hook that returns false should prevent the job from getting queued" do
history = []
@worker = Resque::Worker.new(:jobs)
Resque.enqueue(BeforeEnqueueJobAbort, history)
assert_equal 0, Resque.size(:jobs)
end
end

context "Resque::Job all hooks" do
include PerformJob

Expand Down

0 comments on commit 9016204

Please sign in to comment.