resque 1.24.1 → 1.25.0.pre

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38e90902e4b978a24840fc539e704cb215f5dd2a
4
- data.tar.gz: 26a7b965a985bc1081301509ec15d2ef73212638
3
+ metadata.gz: e28312bcc43dec49cd4dae52b64416413436da85
4
+ data.tar.gz: 489f3640b552d6d9ea6987732b86427a42aec182
5
5
  SHA512:
6
- metadata.gz: 22860bfff69fb573382a48b1a77d5bf7b8f180f4d3ac03096e5a70272cc467c9d9c5f4b764ebf5d22b91c38933f63d1afd2cf98fd3cdf029b7d30c43e97130eb
7
- data.tar.gz: abf28fbbc53bd5f02ee78aa954b87b8c00f32f3c75bdd7e79d977120071975125630038274ea166f2ab0304de94caa8d454f68c3d294a5d932a44c9e59021bc9
6
+ metadata.gz: 3c9d30888178238ed2117f3991d83d204a7cbec53943631637353bc62103b0cd0b63fd2fe93ce60657ed883f1f4664e947745f419f1398671dee5c034fbc3aca
7
+ data.tar.gz: 9c7fda8c5677603ccde7ef5c2c35b19d6b7106d6309e1d3c032afc03730e7db8d80c50400924785d46376784cfc87f2a28797399f4385381d56b667ea10a6f0e
data/HISTORY.md CHANGED
@@ -1,3 +1,28 @@
1
+ ## 1.25.0 (TBD)
2
+ * Updates fork method so [resque-multi-job-forks](https://github.com/stulentsev/resque-multi-job-forks)
3
+ monkey patching works again. See discussion at https://github.com/defunkt/resque/pull/895 for more
4
+ context (@jonhyman)
5
+ * Use Redis.pipelined to group batches of redis commands.
6
+ https://github.com/resque/resque/pull/902 (@jonhyman)
7
+ * Fixed uninitialize constant for the module/class that contains the perform
8
+ method causing job failures to no be reported, #792 (@sideshowcoder)
9
+ * Fix Resque::Failure::Base.all to have the correct signature.
10
+ (@rentalutions)
11
+ * Don't close stdio pipes when daemonizing so as to not hide errors. #967
12
+ (@sideshowcoder)
13
+ * Fix for worker_pids on Windows. #980 (@kzgs)
14
+ * Only prune workers for queues the current worker knows about. #1000
15
+ (!) (@dsabanin)
16
+ * Handle duplicate TERM signals. #988 (@softwaregravy)
17
+ * Fix issue with exiting workers and unintentionally deregistering the
18
+ parent when the forked child exits. #1017 (@magec)
19
+ * Fix encoding errors with local date formatting. #1065 (@katafrakt)
20
+ * Fix CI for 1.8.7 and 1.9.2 modes due to dependencies. #1090
21
+ (@adelcambre)
22
+ * Allow using globs for queue names to listen on, allowing things like
23
+ listening on `staging_*`. #1085 (@adelcambre)
24
+
25
+
1
26
  ## 1.24.1 (2013-3-23)
2
27
 
3
28
  * Adds a default value for `per_page` on resque-server for plugins which add tabs (@jonhyman)
@@ -37,7 +62,6 @@
37
62
  typing purposes (jonhyman)
38
63
  * Fix log formatters not appending a new line (flavorpill)
39
64
  * redirect unauthorized resque-web polling requests to root url (trliner)
40
- * Disable forking with FORK_PER_JOB=false (@tarcieri)
41
65
  * Various resque-web fixes (@tarcieri)
42
66
  * Optional RedisMultiQueue failure backend, can be enabled with
43
67
  FAILURE_BACKEND=redis_multi_queue env var (@tarcieri)
@@ -193,7 +193,7 @@ If a job raises an exception, it is logged and handed off to the
193
193
  `Resque::Failure` module. Failures are logged either locally in Redis
194
194
  or using some different backend.
195
195
 
196
- For example, Resque ships with Hoptoad support.
196
+ For example, Resque ships with Airbrake support.
197
197
 
198
198
  Keep this in mind when writing your jobs: you may want to throw
199
199
  exceptions you would not normally throw in order to assist debugging.
@@ -338,7 +338,7 @@ so using the `resque:workers` rake task:
338
338
 
339
339
  $ COUNT=5 QUEUE=* rake resque:workers
340
340
 
341
- This will spawn five Resque workers, each in its own thread. Hitting
341
+ This will spawn five Resque workers, each in its own process. Hitting
342
342
  ctrl-c should be sufficient to stop them all.
343
343
 
344
344
 
@@ -543,48 +543,6 @@ Choose DelayedJob if:
543
543
  In no way is Resque a "better" DelayedJob, so make sure you pick the
544
544
  tool that's best for your app.
545
545
 
546
-
547
- Installing Redis
548
- ----------------
549
-
550
- Resque requires Redis 0.900 or higher.
551
-
552
- Resque uses Redis' lists for its queues. It also stores worker state
553
- data in Redis.
554
-
555
- #### Homebrew
556
-
557
- If you're on OS X, Homebrew is the simplest way to install Redis:
558
-
559
- $ brew install redis
560
- $ redis-server /usr/local/etc/redis.conf
561
-
562
- You now have a Redis daemon running on 6379.
563
-
564
- #### Via Resque
565
-
566
- Resque includes Rake tasks (thanks to Ezra's redis-rb) that will
567
- install and run Redis for you:
568
-
569
- $ git clone git://github.com/defunkt/resque.git
570
- $ cd resque
571
- $ rake redis:install dtach:install
572
- $ rake redis:start
573
-
574
- Or, if you don't have admin access on your machine:
575
-
576
- $ git clone git://github.com/defunkt/resque.git
577
- $ cd resque
578
- $ PREFIX=<your_prefix> rake redis:install dtach:install
579
- $ rake redis:start
580
-
581
- You now have Redis running on 6379. Wait a second then hit ctrl-\ to
582
- detach and keep it running in the background.
583
-
584
- The demo is probably the best way to figure out how to put the parts
585
- together. But, it's not that hard.
586
-
587
-
588
546
  Resque Dependencies
589
547
  -------------------
590
548
 
@@ -662,7 +620,7 @@ Don't forget you can define a `resque:setup` hook in
662
620
 
663
621
  ### In a Rails 2.x app, as a plugin
664
622
 
665
- $ ./script/plugin install git://github.com/defunkt/resque
623
+ $ ./script/plugin install git://github.com/resque/resque
666
624
 
667
625
  That's it! Resque will automatically be available when your Rails app
668
626
  loads.
@@ -764,11 +722,11 @@ Plugins and Hooks
764
722
  -----------------
765
723
 
766
724
  For a list of available plugins see
767
- <http://wiki.github.com/defunkt/resque/plugins>.
725
+ <http://wiki.github.com/resque/resque/plugins>.
768
726
 
769
727
  If you'd like to write your own plugin, or want to customize Resque
770
728
  using hooks (such as `Resque.after_fork`), see
771
- [docs/HOOKS.md](http://github.com/defunkt/resque/blob/master/docs/HOOKS.md).
729
+ [docs/HOOKS.md](http://github.com/resque/resque/blob/master/docs/HOOKS.md).
772
730
 
773
731
 
774
732
  Namespaces
@@ -820,7 +778,7 @@ send patches for any tweaks or improvements you can make to it.
820
778
  Questions
821
779
  ---------
822
780
 
823
- Please add them to the [FAQ](https://github.com/defunkt/resque/wiki/FAQ) or
781
+ Please add them to the [FAQ](https://github.com/resque/resque/wiki/FAQ) or
824
782
  ask on the Mailing List. The Mailing List is explained further below
825
783
 
826
784
 
@@ -831,7 +789,7 @@ Want to hack on Resque?
831
789
 
832
790
  First clone the repo and run the tests:
833
791
 
834
- git clone git://github.com/defunkt/resque.git
792
+ git clone git://github.com/resque/resque.git
835
793
  cd resque
836
794
  rake test
837
795
 
@@ -884,10 +842,10 @@ The archive can be found at <http://librelist.com/browser/resque/>.
884
842
  Meta
885
843
  ----
886
844
 
887
- * Code: `git clone git://github.com/defunkt/resque.git`
888
- * Home: <http://github.com/defunkt/resque>
889
- * Docs: <http://defunkt.github.com/resque/>
890
- * Bugs: <http://github.com/defunkt/resque/issues>
845
+ * Code: `git clone git://github.com/resque/resque.git`
846
+ * Home: <http://github.com/resque/resque>
847
+ * Docs: <http://resque.github.com/resque/>
848
+ * Bugs: <http://github.com/resque/resque/issues>
891
849
  * List: <resque@librelist.com>
892
850
  * Chat: <irc://irc.freenode.net/resque>
893
851
  * Gems: <http://gemcutter.org/gems/resque>
@@ -902,7 +860,7 @@ Chris Wanstrath :: chris@ozmm.org :: @defunkt
902
860
 
903
861
  [0]: http://github.com/blog/542-introducing-resque
904
862
  [1]: http://help.github.com/forking/
905
- [2]: http://github.com/defunkt/resque/issues
863
+ [2]: http://github.com/resque/resque/issues
906
864
  [sv]: http://semver.org/
907
- [rs]: http://github.com/defunkt/redis-namespace
908
- [cb]: http://wiki.github.com/defunkt/resque/contributing
865
+ [rs]: http://github.com/resque/redis-namespace
866
+ [cb]: http://wiki.github.com/resque/resque/contributing
@@ -21,9 +21,47 @@ require 'resque/plugin'
21
21
  require 'resque/vendor/utf8_util'
22
22
 
23
23
  module Resque
24
- include Helpers
25
24
  extend self
26
25
 
26
+ # Given a Ruby object, returns a string suitable for storage in a
27
+ # queue.
28
+ def encode(object)
29
+ if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
30
+ MultiJson.dump object
31
+ else
32
+ MultiJson.encode object
33
+ end
34
+ end
35
+
36
+ # Given a string, returns a Ruby object.
37
+ def decode(object)
38
+ return unless object
39
+
40
+ begin
41
+ if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
42
+ MultiJson.load object
43
+ else
44
+ MultiJson.decode object
45
+ end
46
+ rescue ::MultiJson::DecodeError => e
47
+ raise Helpers::DecodeException, e.message, e.backtrace
48
+ end
49
+ end
50
+
51
+ extend Forwardable
52
+
53
+ def self.config=(options = {})
54
+ @config = Config.new(options)
55
+ end
56
+
57
+ def self.config
58
+ @config ||= Config.new
59
+ end
60
+
61
+ def self.configure
62
+ yield config
63
+ end
64
+
27
65
  # Accepts:
28
66
  # 1. A 'hostname:port' String
29
67
  # 2. A 'hostname:port:db' String (to select the Redis db)
@@ -169,8 +207,10 @@ module Resque
169
207
  #
170
208
  # Returns nothing
171
209
  def push(queue, item)
172
- watch_queue(queue)
173
- redis.rpush "queue:#{queue}", encode(item)
210
+ redis.pipelined do
211
+ watch_queue(queue)
212
+ redis.rpush "queue:#{queue}", encode(item)
213
+ end
174
214
  end
175
215
 
176
216
  # Pops a job off a queue. Queue name should be a string.
@@ -217,8 +257,10 @@ module Resque
217
257
 
218
258
  # Given a queue name, completely deletes the queue.
219
259
  def remove_queue(queue)
220
- redis.srem(:queues, queue.to_s)
221
- redis.del("queue:#{queue}")
260
+ redis.pipelined do
261
+ redis.srem(:queues, queue.to_s)
262
+ redis.del("queue:#{queue}")
263
+ end
222
264
  end
223
265
 
224
266
  # Used internally to keep track of which queues we've created.
@@ -22,8 +22,8 @@ module Resque
22
22
  # `Resque::Failure::Base`.
23
23
  #
24
24
  # Example use:
25
- # require 'resque/failure/hoptoad'
26
- # Resque::Failure.backend = Resque::Failure::Hoptoad
25
+ # require 'resque/failure/airbrake'
26
+ # Resque::Failure.backend = Resque::Failure::Airbrake
27
27
  def self.backend=(backend)
28
28
  @backend = backend
29
29
  end
@@ -76,8 +76,8 @@ module Resque
76
76
  end
77
77
 
78
78
  # Iterate across all failures with the given options
79
- def self.each(offset = 0, limit = self.count, queue = nil, class_name = nil, &block)
80
- backend.each(offset, limit, queue, class_name, &block)
79
+ def self.each(offset = 0, limit = self.count, queue = nil, class_name = nil, order = 'desc', &block)
80
+ backend.each(offset, limit, queue, class_name, order, &block)
81
81
  end
82
82
 
83
83
  # The string url of the backend's web interface, if any.
@@ -4,14 +4,30 @@ rescue LoadError
4
4
  raise "Can't find 'airbrake' gem. Please add it to your Gemfile or install it."
5
5
  end
6
6
 
7
- require 'resque/failure/thoughtbot'
8
-
9
7
  module Resque
10
8
  module Failure
11
9
  class Airbrake < Base
12
- include Resque::Failure::Thoughtbot
10
+ def self.configure(&block)
11
+ Resque.logger.warn "This actually sets global Airbrake configuration, " \
12
+ "which is probably not what you want. This will be gone in 2.0."
13
+ Resque::Failure.backend = self
14
+ ::Airbrake.configure(&block)
15
+ end
16
+
17
+ def self.count(queue = nil, class_name = nil)
18
+ # We can't get the total # of errors from Airbrake so we fake it
19
+ # by asking Resque how many errors it has seen.
20
+ Stat[:failed]
21
+ end
13
22
 
14
- @klass = ::Airbrake
23
+ def save
24
+ ::Airbrake.notify_or_ignore(exception,
25
+ :parameters => {
26
+ :payload_class => payload['class'].to_s,
27
+ :payload_args => payload['args'].inspect
28
+ }
29
+ )
30
+ end
15
31
  end
16
32
  end
17
33
  end
@@ -42,7 +42,7 @@ module Resque
42
42
  end
43
43
 
44
44
  # Returns a paginated array of failure objects.
45
- def self.all(offset = 0, limit = 1)
45
+ def self.all(offset = 0, limit = 1, queue = nil)
46
46
  []
47
47
  end
48
48
 
@@ -5,7 +5,7 @@ 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 %Z"),
8
+ :failed_at => UTF8Util.clean(Time.now.strftime("%Y/%m/%d %H:%M:%S %Z")),
9
9
  :payload => payload,
10
10
  :exception => exception.class.to_s,
11
11
  :error => UTF8Util.clean(exception.to_s),
@@ -38,10 +38,21 @@ module Resque
38
38
  Resque.list_range(:failed, offset, limit)
39
39
  end
40
40
 
41
- def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil)
42
- Array(all(offset, limit, queue)).each_with_index do |item, i|
41
+ def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
42
+ all_items = Array(all(offset, limit, queue))
43
+ reversed = false
44
+ if order.eql? 'desc'
45
+ all_items.reverse!
46
+ reversed = true
47
+ end
48
+ all_items.each_with_index do |item, i|
43
49
  if !class_name || (item['payload'] && item['payload']['class'] == class_name)
44
- yield offset + i, item
50
+ if reversed
51
+ id = (all_items.length - 1) - (offset + i)
52
+ else
53
+ id = offset + i
54
+ end
55
+ yield id, item
45
56
  end
46
57
  end
47
58
  end
@@ -33,17 +33,20 @@ module Resque
33
33
  end
34
34
  end
35
35
 
36
- def self.all(offset = 0, limit = 1, queue = :failed)
37
- Resque.list_range(queue, offset, limit)
36
+ def self.all(offset = 0, limit = 1, queue = :failed, order = 'desc')
37
+ Resque.list_range(queue, offset, limit, order)
38
38
  end
39
39
 
40
40
  def self.queues
41
41
  Array(Resque.redis.smembers(:failed_queues))
42
42
  end
43
43
 
44
- def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil)
45
- items = all(offset, limit, queue)
44
+ def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
45
+ items = all(offset, limit, queue, order)
46
46
  items = [items] unless items.is_a? Array
47
+ if order.eql? 'desc'
48
+ items.reverse!
49
+ end
47
50
  items.each_with_index do |item, i|
48
51
  if !class_name || (item['payload'] && item['payload']['class'] == class_name)
49
52
  yield offset + i, item
@@ -11,6 +11,14 @@ 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
+
14
22
  class DecodeException < StandardError; end
15
23
 
16
24
  # Direct access to the Redis instance.
@@ -26,7 +34,6 @@ module Resque
26
34
  else
27
35
  MultiJson.encode object
28
36
  end
29
-
30
37
  end
31
38
 
32
39
  # Given a string, returns a Ruby object.
@@ -12,8 +12,110 @@ 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
+ def redis
16
+ Resque.redis
17
+ end
18
+
19
+ def self.redis
20
+ Resque.redis
21
+ end
22
+
23
+ # Given a Ruby object, returns a string suitable for storage in a
24
+ # queue.
25
+ 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
31
+ end
32
+
33
+ # Given a string, returns a Ruby object.
34
+ 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
46
+ end
47
+
48
+ # Given a Ruby object, returns a string suitable for storage in a
49
+ # queue.
50
+ 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
56
+ end
57
+
58
+ # Given a string, returns a Ruby object.
59
+ 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
71
+ end
72
+
73
+ # Given a word with dashes, returns a camel cased version of it.
74
+ #
75
+ # classify('job-name') # => 'JobName'
76
+ def classify(dashed_word)
77
+ dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
78
+ 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
+
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
118
+ end
17
119
 
18
120
  # Raise Resque::Job::DontPerform from a before_perform hook to
19
121
  # abort the job.
@@ -166,6 +268,19 @@ module Resque
166
268
  @payload_class ||= constantize(@payload['class'])
167
269
  end
168
270
 
271
+ # Returns the payload class as a string without raising NameError
272
+ def payload_class_name
273
+ payload_class.to_s
274
+ rescue NameError
275
+ 'No Name'
276
+ end
277
+
278
+ def has_payload_class?
279
+ payload_class != Object
280
+ rescue NameError
281
+ false
282
+ end
283
+
169
284
  # Returns an array of args represented in this job's payload.
170
285
  def args
171
286
  @payload['args']
@@ -220,7 +335,9 @@ module Resque
220
335
  def run_failure_hooks(exception)
221
336
  begin
222
337
  job_args = args || []
223
- failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) } unless @failure_hooks_ran
338
+ if has_payload_class?
339
+ failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) } unless @failure_hooks_ran
340
+ end
224
341
  ensure
225
342
  @failure_hooks_ran = true
226
343
  end