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 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!`.
@@ -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](http://img.skitch.com/20091104-tqh5pgkwgbskjbk7qbtmpesnyw.jpg)
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 redis redis-namespace yajl-ruby vegas sinatra
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
 
@@ -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|
@@ -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
@@ -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
- if defined? Yajl
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
- if defined? Yajl
26
- begin
27
- Yajl::Parser.parse(object, :check_utf8 => false)
28
- rescue Yajl::ParseError => e
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
 
@@ -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
@@ -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
@@ -40,3 +40,10 @@ namespace :resque do
40
40
  threads.each { |thread| thread.join }
41
41
  end
42
42
  end
43
+
44
+ # Preload app files
45
+ task :environment do
46
+ Dir['app/**/*.rb'].each do |file|
47
+ require file
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Resque
2
- Version = VERSION = '1.17.1'
2
+ Version = VERSION = '1.18.0'
3
3
  end
@@ -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.to_s,
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 array of string pids of all the other workers on this
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
@@ -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: 81
4
+ hash: 95
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 17
9
- - 1
10
- version: 1.17.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-05-27 00:00:00 -07:00
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: json
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: 3
77
+ hash: 15
86
78
  segments:
87
79
  - 1
88
- - 6
89
- version: "1.6"
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"