diff --git a/Gemfile b/Gemfile index 9b421313b..f759d235b 100644 --- a/Gemfile +++ b/Gemfile @@ -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 diff --git a/README.markdown b/README.markdown index 6bea746a0..66407daa5 100644 --- a/README.markdown +++ b/README.markdown @@ -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 @@ -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. @@ -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 @@ -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 ------------- diff --git a/docs/HOOKS.md b/docs/HOOKS.md index c091a60e3..c6a5f66d9 100644 --- a/docs/HOOKS.md +++ b/docs/HOOKS.md @@ -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. diff --git a/examples/god/resque.god b/examples/god/resque.god index d28c90088..a2eaf0c11 100644 --- a/examples/god/resque.god +++ b/examples/god/resque.god @@ -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 diff --git a/lib/resque.rb b/lib/resque.rb index 20fb7e4f1..a3ec9416b 100644 --- a/lib/resque.rb +++ b/lib/resque.rb @@ -1,11 +1,5 @@ require 'redis/namespace' -begin - require 'yajl' -rescue LoadError - require 'json' -end - require 'resque/version' require 'resque/errors' @@ -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| diff --git a/lib/resque/failure/redis.rb b/lib/resque/failure/redis.rb index fc060764e..8ebee78c1 100644 --- a/lib/resque/failure/redis.rb +++ b/lib/resque/failure/redis.rb @@ -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 } @@ -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 diff --git a/lib/resque/helpers.rb b/lib/resque/helpers.rb index 3ac57eeec..1d045aa07 100644 --- a/lib/resque/helpers.rb +++ b/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 @@ -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 diff --git a/lib/resque/plugin.rb b/lib/resque/plugin.rb index 3152dd4bc..5f9c598c5 100644 --- a/lib/resque/plugin.rb +++ b/lib/resque/plugin.rb @@ -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 diff --git a/lib/resque/worker.rb b/lib/resque/worker.rb index 2ed7614d2..c4d7021d8 100644 --- a/lib/resque/worker.rb +++ b/lib/resque/worker.rb @@ -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 diff --git a/resque.gemspec b/resque.gemspec index 8c4df9651..a3c913b9e 100644 --- a/resque.gemspec +++ b/resque.gemspec @@ -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 = <