resque 1.26.pre.0 → 1.26.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.

Files changed (42) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +29 -16
  3. data/README.markdown +60 -6
  4. data/Rakefile +4 -17
  5. data/bin/resque-web +4 -0
  6. data/lib/resque.rb +116 -16
  7. data/lib/resque/errors.rb +1 -0
  8. data/lib/resque/failure.rb +11 -5
  9. data/lib/resque/failure/multiple.rb +6 -1
  10. data/lib/resque/failure/redis.rb +13 -4
  11. data/lib/resque/failure/redis_multi_queue.rb +14 -6
  12. data/lib/resque/helpers.rb +5 -64
  13. data/lib/resque/job.rb +25 -79
  14. data/lib/resque/logging.rb +1 -1
  15. data/lib/resque/plugin.rb +22 -10
  16. data/lib/resque/server.rb +35 -7
  17. data/lib/resque/server/helpers.rb +1 -1
  18. data/lib/resque/server/views/failed.erb +1 -1
  19. data/lib/resque/server/views/failed_job.erb +3 -3
  20. data/lib/resque/server/views/failed_queues_overview.erb +3 -3
  21. data/lib/resque/server/views/workers.erb +2 -0
  22. data/lib/resque/server/views/working.erb +4 -5
  23. data/lib/resque/tasks.rb +7 -25
  24. data/lib/resque/vendor/utf8_util/utf8_util_19.rb +1 -0
  25. data/lib/resque/version.rb +1 -1
  26. data/lib/resque/worker.rb +225 -116
  27. metadata +68 -90
  28. data/test/airbrake_test.rb +0 -27
  29. data/test/dump.rdb +0 -0
  30. data/test/failure_base_test.rb +0 -15
  31. data/test/job_hooks_test.rb +0 -464
  32. data/test/job_plugins_test.rb +0 -230
  33. data/test/logging_test.rb +0 -24
  34. data/test/plugin_test.rb +0 -116
  35. data/test/redis-test-cluster.conf +0 -115
  36. data/test/redis-test.conf +0 -115
  37. data/test/resque-web_test.rb +0 -59
  38. data/test/resque_failure_redis_test.rb +0 -19
  39. data/test/resque_hook_test.rb +0 -165
  40. data/test/resque_test.rb +0 -278
  41. data/test/test_helper.rb +0 -198
  42. data/test/worker_test.rb +0 -1015
@@ -27,6 +27,11 @@ module Resque
27
27
  classes.first.count(*args)
28
28
  end
29
29
 
30
+ # Returns an array of all available failure queues
31
+ def self.queues
32
+ classes.first.queues
33
+ end
34
+
30
35
  # Returns a paginated array of failure objects.
31
36
  def self.all(*args)
32
37
  classes.first.all(*args)
@@ -51,7 +56,7 @@ module Resque
51
56
  classes.first.requeue(*args)
52
57
  end
53
58
 
54
- def self.remove(index)
59
+ def self.remove(index, queue)
55
60
  classes.each { |klass| klass.remove(index) }
56
61
  end
57
62
  end
@@ -39,7 +39,7 @@ module Resque
39
39
  end
40
40
 
41
41
  def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
42
- all_items = Array(all(offset, limit, queue))
42
+ all_items = limit == 1 ? [all(offset,limit,queue)] : Array(all(offset, limit, queue))
43
43
  reversed = false
44
44
  if order.eql? 'desc'
45
45
  all_items.reverse!
@@ -48,7 +48,7 @@ module Resque
48
48
  all_items.each_with_index do |item, i|
49
49
  if !class_name || (item['payload'] && item['payload']['class'] == class_name)
50
50
  if reversed
51
- id = (all_items.length - 1) - (offset + i)
51
+ id = (all_items.length - 1) + (offset - i)
52
52
  else
53
53
  id = offset + i
54
54
  end
@@ -62,14 +62,16 @@ module Resque
62
62
  Resque.redis.del(:failed)
63
63
  end
64
64
 
65
- def self.requeue(id)
65
+ def self.requeue(id, queue = nil)
66
+ check_queue(queue)
66
67
  item = all(id)
67
68
  item['retried_at'] = Time.now.strftime("%Y/%m/%d %H:%M:%S")
68
69
  Resque.redis.lset(:failed, id, Resque.encode(item))
69
70
  Job.create(item['queue'], item['payload']['class'], *item['payload']['args'])
70
71
  end
71
72
 
72
- def self.remove(id)
73
+ def self.remove(id, queue = nil)
74
+ check_queue(queue)
73
75
  sentinel = ""
74
76
  Resque.redis.lset(:failed, id, sentinel)
75
77
  Resque.redis.lrem(:failed, 1, sentinel)
@@ -83,6 +85,12 @@ module Resque
83
85
  end
84
86
  end
85
87
 
88
+ def self.requeue_all
89
+ count.times do |num|
90
+ requeue(num)
91
+ end
92
+ end
93
+
86
94
  def self.remove_queue(queue)
87
95
  i = 0
88
96
  while job = all(i)
@@ -103,6 +111,7 @@ module Resque
103
111
  index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
104
112
  backtrace.first(index.to_i)
105
113
  end
114
+
106
115
  end
107
116
  end
108
117
  end
@@ -33,8 +33,8 @@ module Resque
33
33
  end
34
34
  end
35
35
 
36
- def self.all(offset = 0, limit = 1, queue = :failed, order = 'desc')
37
- Resque.list_range(queue, offset, limit, order)
36
+ def self.all(offset = 0, limit = 1, queue = :failed)
37
+ Resque.list_range(queue, offset, limit)
38
38
  end
39
39
 
40
40
  def self.queues
@@ -42,20 +42,24 @@ module Resque
42
42
  end
43
43
 
44
44
  def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
45
- items = all(offset, limit, queue, order)
45
+ items = all(offset, limit, queue)
46
46
  items = [items] unless items.is_a? Array
47
+ reversed = false
47
48
  if order.eql? 'desc'
48
49
  items.reverse!
50
+ reversed = true
49
51
  end
50
52
  items.each_with_index do |item, i|
51
53
  if !class_name || (item['payload'] && item['payload']['class'] == class_name)
52
- yield offset + i, item
54
+ id = reversed ? (items.length - 1) - (offset + i) : offset + i
55
+ yield id, item
53
56
  end
54
57
  end
55
58
  end
56
59
 
57
- def self.clear(queue = :failed)
58
- Resque.redis.del(queue)
60
+ def self.clear(queue = nil)
61
+ queues = queue ? Array(queue) : self.queues
62
+ queues.each { |queue| Resque.redis.del(queue) }
59
63
  end
60
64
 
61
65
  def self.requeue(id, queue = :failed)
@@ -76,6 +80,10 @@ module Resque
76
80
  each(0, count(failure_queue), failure_queue) { |id, _| requeue(id, failure_queue) }
77
81
  end
78
82
 
83
+ def self.requeue_all
84
+ queues.each { |queue| requeue_queue(Resque::Failure.job_queue_name(queue)) }
85
+ end
86
+
79
87
  def self.remove_queue(queue)
80
88
  Resque.redis.del(Resque::Failure.failure_queue_name(queue))
81
89
  end
@@ -11,14 +11,6 @@ end
11
11
  module Resque
12
12
  # Methods used by various classes in Resque.
13
13
  module Helpers
14
- def self.extended(parent_class)
15
- warn("Resque::Helpers will be gone with no replacement in Resque 2.0.0.")
16
- end
17
-
18
- def self.included(parent_class)
19
- warn("Resque::Helpers will be gone with no replacement in Resque 2.0.0.")
20
- end
21
-
22
14
  class DecodeException < StandardError; end
23
15
 
24
16
  # Direct access to the Redis instance.
@@ -35,73 +27,22 @@ module Resque
35
27
  # Given a Ruby object, returns a string suitable for storage in a
36
28
  # queue.
37
29
  def encode(object)
38
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
39
- MultiJson.dump object
40
- else
41
- MultiJson.encode object
42
- end
30
+ Resque.encode(object)
43
31
  end
44
32
 
45
33
  # Given a string, returns a Ruby object.
46
34
  def decode(object)
47
- return unless object
48
-
49
- begin
50
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
51
- MultiJson.load object
52
- else
53
- MultiJson.decode object
54
- end
55
- rescue ::MultiJson::DecodeError => e
56
- raise DecodeException, e.message, e.backtrace
57
- end
35
+ Resque.decode(object)
58
36
  end
59
37
 
60
38
  # Given a word with dashes, returns a camel cased version of it.
61
- #
62
- # classify('job-name') # => 'JobName'
63
39
  def classify(dashed_word)
64
- dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
40
+ Resque.classify(dashed_word)
65
41
  end
66
42
 
67
- # Tries to find a constant with the name specified in the argument string:
68
- #
69
- # constantize("Module") # => Module
70
- # constantize("Test::Unit") # => Test::Unit
71
- #
72
- # The name is assumed to be the one of a top-level constant, no matter
73
- # whether it starts with "::" or not. No lexical context is taken into
74
- # account:
75
- #
76
- # C = 'outside'
77
- # module M
78
- # C = 'inside'
79
- # C # => 'inside'
80
- # constantize("C") # => 'outside', same as ::C
81
- # end
82
- #
83
- # NameError is raised when the constant is unknown.
43
+ # Tries to find a constant with the name specified in the argument string
84
44
  def constantize(camel_cased_word)
85
- camel_cased_word = camel_cased_word.to_s
86
-
87
- if camel_cased_word.include?('-')
88
- camel_cased_word = classify(camel_cased_word)
89
- end
90
-
91
- names = camel_cased_word.split('::')
92
- names.shift if names.empty? || names.first.empty?
93
-
94
- constant = Object
95
- names.each do |name|
96
- args = Module.method(:const_get).arity != 1 ? [false] : []
97
-
98
- if constant.const_defined?(name, *args)
99
- constant = constant.const_get(name)
100
- else
101
- constant = constant.const_missing(name)
102
- end
103
- end
104
- constant
45
+ Resque.constantize(camel_cased_word)
105
46
  end
106
47
  end
107
48
  end
@@ -12,6 +12,8 @@ module Resque
12
12
  # klass = Resque::Job.constantize(job.payload['class'])
13
13
  # klass.perform(*job.payload['args'])
14
14
  class Job
15
+ include Helpers
16
+ extend Helpers
15
17
  def redis
16
18
  Resque.redis
17
19
  end
@@ -23,98 +25,33 @@ module Resque
23
25
  # Given a Ruby object, returns a string suitable for storage in a
24
26
  # queue.
25
27
  def encode(object)
26
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
27
- MultiJson.dump object
28
- else
29
- MultiJson.encode object
30
- end
28
+ Resque.encode(object)
31
29
  end
32
30
 
33
31
  # Given a string, returns a Ruby object.
34
32
  def decode(object)
35
- return unless object
36
-
37
- begin
38
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
39
- MultiJson.load object
40
- else
41
- MultiJson.decode object
42
- end
43
- rescue ::MultiJson::DecodeError => e
44
- raise DecodeException, e.message, e.backtrace
45
- end
33
+ Resque.decode(object)
46
34
  end
47
35
 
48
36
  # Given a Ruby object, returns a string suitable for storage in a
49
37
  # queue.
50
38
  def self.encode(object)
51
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
52
- MultiJson.dump object
53
- else
54
- MultiJson.encode object
55
- end
39
+ Resque.encode(object)
56
40
  end
57
41
 
58
42
  # Given a string, returns a Ruby object.
59
43
  def self.decode(object)
60
- return unless object
61
-
62
- begin
63
- if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
64
- MultiJson.load object
65
- else
66
- MultiJson.decode object
67
- end
68
- rescue ::MultiJson::DecodeError => e
69
- raise DecodeException, e.message, e.backtrace
70
- end
44
+ Resque.decode(object)
71
45
  end
72
46
 
73
47
  # Given a word with dashes, returns a camel cased version of it.
74
- #
75
- # classify('job-name') # => 'JobName'
76
48
  def classify(dashed_word)
77
- dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
49
+ Resque.classify(dashed_word)
78
50
  end
79
-
80
- # Tries to find a constant with the name specified in the argument string:
81
- #
82
- # constantize("Module") # => Module
83
- # constantize("Test::Unit") # => Test::Unit
84
- #
85
- # The name is assumed to be the one of a top-level constant, no matter
86
- # whether it starts with "::" or not. No lexical context is taken into
87
- # account:
88
- #
89
- # C = 'outside'
90
- # module M
91
- # C = 'inside'
92
- # C # => 'inside'
93
- # constantize("C") # => 'outside', same as ::C
94
- # end
95
- #
96
- # NameError is raised when the constant is unknown.
97
- def constantize(camel_cased_word)
98
- camel_cased_word = camel_cased_word.to_s
99
-
100
- if camel_cased_word.include?('-')
101
- camel_cased_word = classify(camel_cased_word)
102
- end
103
-
104
- names = camel_cased_word.split('::')
105
- names.shift if names.empty? || names.first.empty?
106
-
107
- constant = Object
108
- names.each do |name|
109
- args = Module.method(:const_get).arity != 1 ? [false] : []
110
51
 
111
- if constant.const_defined?(name, *args)
112
- constant = constant.const_get(name)
113
- else
114
- constant = constant.const_missing(name)
115
- end
116
- end
117
- constant
52
+ # Tries to find a constant with the name specified in the argument string
53
+ def constantize(camel_cased_word)
54
+ Resque.constantize(camel_cased_word)
118
55
  end
119
56
 
120
57
  # Raise Resque::Job::DontPerform from a before_perform hook to
@@ -289,12 +226,17 @@ module Resque
289
226
  # Given an exception object, hands off the needed parameters to
290
227
  # the Failure module.
291
228
  def fail(exception)
292
- run_failure_hooks(exception)
293
- Failure.create \
294
- :payload => payload,
295
- :exception => exception,
296
- :worker => worker,
297
- :queue => queue
229
+ begin
230
+ run_failure_hooks(exception)
231
+ rescue Exception => e
232
+ raise e
233
+ ensure
234
+ Failure.create \
235
+ :payload => payload,
236
+ :exception => exception,
237
+ :worker => worker,
238
+ :queue => queue
239
+ end
298
240
  end
299
241
 
300
242
  # Creates an identical job, essentially placing this job back on
@@ -338,6 +280,10 @@ module Resque
338
280
  if has_payload_class?
339
281
  failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) } unless @failure_hooks_ran
340
282
  end
283
+ rescue Exception => e
284
+ error_message = "Additional error (#{e.class}: #{e}) occurred in running failure hooks for job #{inspect}\n" \
285
+ "Original error that caused job failure was #{e.class}: #{exception.class}: #{exception.message}"
286
+ raise RuntimeError.new(error_message)
341
287
  ensure
342
288
  @failure_hooks_ran = true
343
289
  end
@@ -15,4 +15,4 @@ module Resque
15
15
  def error(message); Logging.log :error, message; end
16
16
  def fatal(message); Logging.log :fatal, message; end
17
17
  end
18
- end
18
+ end
@@ -11,56 +11,68 @@ module Resque
11
11
  hooks = before_hooks(plugin) + around_hooks(plugin) + after_hooks(plugin)
12
12
 
13
13
  hooks.each do |hook|
14
- if hook =~ /perform$/
14
+ if hook.to_s.end_with?("perform")
15
15
  raise LintError, "#{plugin}.#{hook} is not namespaced"
16
16
  end
17
17
  end
18
18
 
19
19
  failure_hooks(plugin).each do |hook|
20
- if hook =~ /failure$/
20
+ if hook.to_s.end_with?("failure")
21
21
  raise LintError, "#{plugin}.#{hook} is not namespaced"
22
22
  end
23
23
  end
24
24
  end
25
25
 
26
+ @job_methods = {}
27
+ def job_methods(job)
28
+ @job_methods[job] ||= job.methods.collect{|m| m.to_s}
29
+ end
30
+
31
+ # Given an object, and a method prefix, returns a list of methods prefixed
32
+ # with that name (hook names).
33
+ def get_hook_names(job, hook_method_prefix)
34
+ methods = (job.respond_to?(:hooks) && job.hooks) || job_methods(job)
35
+ methods.select{|m| m.start_with?(hook_method_prefix)}.sort
36
+ end
37
+
26
38
  # Given an object, returns a list `before_perform` hook names.
27
39
  def before_hooks(job)
28
- job.methods.grep(/^before_perform/).sort
40
+ get_hook_names(job, 'before_perform')
29
41
  end
30
42
 
31
43
  # Given an object, returns a list `around_perform` hook names.
32
44
  def around_hooks(job)
33
- job.methods.grep(/^around_perform/).sort
45
+ get_hook_names(job, 'around_perform')
34
46
  end
35
47
 
36
48
  # Given an object, returns a list `after_perform` hook names.
37
49
  def after_hooks(job)
38
- job.methods.grep(/^after_perform/).sort
50
+ get_hook_names(job, 'after_perform')
39
51
  end
40
52
 
41
53
  # Given an object, returns a list `on_failure` hook names.
42
54
  def failure_hooks(job)
43
- job.methods.grep(/^on_failure/).sort
55
+ get_hook_names(job, 'on_failure')
44
56
  end
45
57
 
46
58
  # Given an object, returns a list `after_enqueue` hook names.
47
59
  def after_enqueue_hooks(job)
48
- job.methods.grep(/^after_enqueue/).sort
60
+ get_hook_names(job, 'after_enqueue')
49
61
  end
50
62
 
51
63
  # Given an object, returns a list `before_enqueue` hook names.
52
64
  def before_enqueue_hooks(job)
53
- job.methods.grep(/^before_enqueue/).sort
65
+ get_hook_names(job, 'before_enqueue')
54
66
  end
55
67
 
56
68
  # Given an object, returns a list `after_dequeue` hook names.
57
69
  def after_dequeue_hooks(job)
58
- job.methods.grep(/^after_dequeue/).sort
70
+ get_hook_names(job, 'after_dequeue')
59
71
  end
60
72
 
61
73
  # Given an object, returns a list `before_dequeue` hook names.
62
74
  def before_dequeue_hooks(job)
63
- job.methods.grep(/^before_dequeue/).sort
75
+ get_hook_names(job, 'before_dequeue')
64
76
  end
65
77
  end
66
78
  end