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
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f654ccc902abcf33c2340b1e7a718224404880aa
4
+ data.tar.gz: bb83a2fabd7698745fcde434567c85f4852b48a4
5
+ SHA512:
6
+ metadata.gz: b4c51510f6ce42a7c4b2b31bda3c5758d91e1503fbdc7fac70ae976ef02aa3d519258e38da5a74def54db4487eb673df309b16b3b09b9bc9870beb844f474dd5
7
+ data.tar.gz: bda8063a0120e1a9e12c483b0a8c0aac1c472104f129f36d1867d2b75663ab2d712c6c965d1735edc1b3f436cc4272f9d1f9037cc3af1e5608c9ada00592949e
data/HISTORY.md CHANGED
@@ -1,29 +1,42 @@
1
- ## 1.26.0 (TBD)
2
-
3
- * FIX: use Socket.hostname instead of shelling out in order to avoid
4
- errors caused when too many workers are started simultaneously. #1152
5
- Backport of fix from 2.x master. (@hone, @RunsFor)
6
- * FIX: infinite recusion when applying a workaround to make resque
7
- backwards-compatible with <= 1.24. #1150 (@yaauie)
8
- * FIX: add/fix test coverage for worker pruning and be a little more
9
- aggressive in what we prune. (@yaauie)
10
- * FIX: require yaml library for show_args support in resque-web. #1143
11
- (@yaauie)
12
- * FIX: README and documentation link fixes. #1130 (@cade)
13
- * Feature: implementation of Backend connection with Hash, using the same
14
- connection hash supported by redis-rb #1140 (@lucidstack)
1
+ ## 1.27.0 (TBD)
2
+
3
+ None yet!
4
+
5
+ ## 1.26.0 (2016-03-10)
6
+
7
+ This changelog is a bit incomplete. We will be much stricter about the changelog for
8
+ the next release.
9
+
10
+ * rake: when BACKGROUND, ensure worker.reconnect after daemonizing (@yaauie)
11
+ * worker: when searching workers, Worker#pid properly reflects pid of the found
12
+ worker instead of the current pid. (@yaauie)
13
+ * Add support for RESQUE_PROCLINE_PREFIX environment variable to prefix
14
+ procline strings with a static identifier. (@rbroemeling)
15
+ * Resque::Worker logs errors at the correct logging level (@chrisccerami)
16
+
17
+ ## 1.25.2 (2014-3-3)
18
+
19
+ * Respect TERM_CHILD setting when not forking (@ggilder)
20
+ * implementation of backend connection with a hash (Andrea Rossi)
21
+ * require yaml for show_args support (@yaauie)
22
+ * use redis-namespace 1.3 (Andrea Rossi)
23
+ * fix DOCS link in README (@cade)
24
+ * Fix worker prune test to actually run its assertion & cover reality. (@yaauie)
25
+ * Eliminate infinite recursion when Resque::Helpers mixed into Resque (@yaml)
26
+ * use ruby, avoid shelling out. google++ (@hone)
27
+ * Failed Assertions Don't Fail Tests :rage: (@yaauie)
15
28
 
16
29
  ## 1.25.1 (2013-9-26)
17
30
 
18
31
  * Actually require Forwardable from the standard library.
19
32
 
20
- ## 1.25.0 (TBD)
33
+ ## 1.25.0 (2013-4-16)
21
34
  * Updates fork method so [resque-multi-job-forks](https://github.com/stulentsev/resque-multi-job-forks)
22
35
  monkey patching works again. See discussion at https://github.com/defunkt/resque/pull/895 for more
23
36
  context (@jonhyman)
24
37
  * Use Redis.pipelined to group batches of redis commands.
25
38
  https://github.com/resque/resque/pull/902 (@jonhyman)
26
- * Fixed uninitialize constant for the module/class that contains the perform
39
+ * Fixed uninitialize constant for the module/class that contains the perform
27
40
  method causing job failures to no be reported, #792 (@sideshowcoder)
28
41
  * Fix Resque::Failure::Base.all to have the correct signature.
29
42
  (@rentalutions)
@@ -1,6 +1,10 @@
1
1
  Resque
2
2
  ======
3
3
 
4
+ [![Gem Version](https://badge.fury.io/rb/resque.svg)](https://rubygems.org/gems/resque)
5
+ [![Build Status](https://travis-ci.org/resque/resque.svg)](https://travis-ci.org/resque/resque)
6
+ [![Coverage Status](https://coveralls.io/repos/github/resque/resque/badge.svg?branch=1-x-stable)](https://coveralls.io/r/resque/resque?branch=1-x-stable)
7
+
4
8
  Resque (pronounced like "rescue") is a Redis-backed library for creating
5
9
  background jobs, placing those jobs on multiple queues, and processing
6
10
  them later.
@@ -193,7 +197,18 @@ If a job raises an exception, it is logged and handed off to the
193
197
  `Resque::Failure` module. Failures are logged either locally in Redis
194
198
  or using some different backend.
195
199
 
196
- For example, Resque ships with Airbrake support.
200
+ For example, Resque ships with Airbrake support. To configure it, put
201
+ the following into an initialisation file or into your rake job:
202
+
203
+ ``` ruby
204
+ # send errors which occur in background jobs to redis and airbrake
205
+ require 'resque/failure/multiple'
206
+ require 'resque/failure/redis'
207
+ require 'resque/failure/airbrake'
208
+
209
+ Resque::Failure::Multiple.classes = [Resque::Failure::Redis, Resque::Failure::Airbrake]
210
+ Resque::Failure.backend = Resque::Failure::Multiple
211
+ ```
197
212
 
198
213
  Keep this in mind when writing your jobs: you may want to throw
199
214
  exceptions you would not normally throw in order to assist debugging.
@@ -258,6 +273,13 @@ variable.
258
273
 
259
274
  $ VVERBOSE=1 QUEUE=file_serve rake environment resque:work
260
275
 
276
+ If you want Resque to log to a file, in Rails do:
277
+
278
+ ```ruby
279
+ # config/initializers/resque.rb
280
+ Resque.logger = Logger.new(Rails.root.join('log', "#{Rails.env}_resque.log"))
281
+ ```
282
+
261
283
  ### Process IDs (PIDs)
262
284
 
263
285
  There are scenarios where it's helpful to record the PID of a resque
@@ -429,9 +451,41 @@ then `CONT` to start it again.
429
451
 
430
452
  ### Mysql::Error: MySQL server has gone away
431
453
 
432
- If your workers remain idle for too long they may lose their MySQL
433
- connection. If that happens we recommend using [this
434
- Gist](http://gist.github.com/238999).
454
+ If your workers remain idle for too long they may lose their MySQL connection. Depending on your version of Rails, we recommend the following:
455
+
456
+ #### Rails 3.x
457
+ In your `perform` method, add the following line:
458
+
459
+ ``` ruby
460
+ class MyTask
461
+ def self.perform
462
+ ActiveRecord::Base.verify_active_connections!
463
+ # rest of your code
464
+ end
465
+ end
466
+ ```
467
+
468
+ The Rails doc says the following about `verify_active_connections!`:
469
+
470
+ Verify active connections and remove and disconnect connections associated with stale threads.
471
+
472
+ #### Rails 4.x
473
+
474
+ In your `perform` method, instead of `verify_active_connections!`, use:
475
+
476
+ ``` ruby
477
+ class MyTask
478
+ def self.perform
479
+ ActiveRecord::Base.clear_active_connections!
480
+ # rest of your code
481
+ end
482
+ end
483
+ ```
484
+
485
+ From the Rails docs on [`clear_active_connections!`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/ConnectionHandler.html#method-i-clear_active_connections-21):
486
+
487
+ Returns any connections in use by the current thread back to the pool, and also returns connections to the pool cached by threads that are no longer alive.
488
+
435
489
 
436
490
 
437
491
  The Front End
@@ -440,7 +494,7 @@ The Front End
440
494
  Resque comes with a Sinatra-based front end for seeing what's up with
441
495
  your queue.
442
496
 
443
- ![The Front End](https://img.skitch.com/20110528-pc67a8qsfapgjxf5gagxd92fcu.png)
497
+ ![The Front End](https://camo.githubusercontent.com/64d150a243987ffbc33f588bd6d7722a0bb8d69a/687474703a2f2f7475746f7269616c732e6a756d7073746172746c61622e636f6d2f696d616765732f7265737175655f6f766572766965772e706e67)
444
498
 
445
499
  ### Standalone
446
500
 
@@ -818,7 +872,7 @@ sort it out.
818
872
  Contributing
819
873
  ------------
820
874
 
821
- Read the [Contributing][cb] wiki page first.
875
+ Read [CONTRIBUTING.md](CONTRIBUTING.md) first.
822
876
 
823
877
  Once you've made your great commits:
824
878
 
data/Rakefile CHANGED
@@ -11,6 +11,10 @@ def command?(command)
11
11
  system("type #{command} > /dev/null 2>&1")
12
12
  end
13
13
 
14
+ require 'rubygems'
15
+ require 'bundler/setup'
16
+ require 'bundler/gem_tasks'
17
+
14
18
 
15
19
  #
16
20
  # Tests
@@ -51,20 +55,3 @@ begin
51
55
  require 'sdoc_helpers'
52
56
  rescue LoadError
53
57
  end
54
-
55
-
56
- #
57
- # Publishing
58
- #
59
-
60
- desc "Push a new version to Gemcutter"
61
- task :publish do
62
- require 'resque/version'
63
-
64
- sh "gem build resque.gemspec"
65
- sh "gem push resque-#{Resque::Version}.gem"
66
- sh "git tag v#{Resque::Version}"
67
- sh "git push origin v#{Resque::Version}"
68
- sh "git push origin master"
69
- sh "git clean -fd"
70
- end
@@ -24,4 +24,8 @@ Vegas::Runner.new(Resque::Server, 'resque-web', {
24
24
  runner.logger.info "Using Redis connection '#{redis_conf}'"
25
25
  Resque.redis = redis_conf
26
26
  }
27
+ opts.on('-a url-prefix', "--append url-prefix", "set reverse_proxy friendly prefix to links") {|url_prefix|
28
+ runner.logger.info "Using URL Prefix '#{url_prefix}'"
29
+ Resque::Server.url_prefix = url_prefix
30
+ }
27
31
  end
@@ -22,6 +22,7 @@ require 'resque/plugin'
22
22
  require 'resque/vendor/utf8_util'
23
23
 
24
24
  module Resque
25
+ include Helpers
25
26
  extend self
26
27
 
27
28
  # Given a Ruby object, returns a string suitable for storage in a
@@ -49,20 +50,55 @@ module Resque
49
50
  end
50
51
  end
51
52
 
52
- extend ::Forwardable
53
-
54
- def self.config=(options = {})
55
- @config = Config.new(options)
53
+ # Given a word with dashes, returns a camel cased version of it.
54
+ #
55
+ # classify('job-name') # => 'JobName'
56
+ def classify(dashed_word)
57
+ dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
56
58
  end
57
59
 
58
- def self.config
59
- @config ||= Config.new
60
- end
60
+ # Tries to find a constant with the name specified in the argument string:
61
+ #
62
+ # constantize("Module") # => Module
63
+ # constantize("Test::Unit") # => Test::Unit
64
+ #
65
+ # The name is assumed to be the one of a top-level constant, no matter
66
+ # whether it starts with "::" or not. No lexical context is taken into
67
+ # account:
68
+ #
69
+ # C = 'outside'
70
+ # module M
71
+ # C = 'inside'
72
+ # C # => 'inside'
73
+ # constantize("C") # => 'outside', same as ::C
74
+ # end
75
+ #
76
+ # NameError is raised when the constant is unknown.
77
+ def constantize(camel_cased_word)
78
+ camel_cased_word = camel_cased_word.to_s
79
+
80
+ if camel_cased_word.include?('-')
81
+ camel_cased_word = classify(camel_cased_word)
82
+ end
83
+
84
+ names = camel_cased_word.split('::')
85
+ names.shift if names.empty? || names.first.empty?
61
86
 
62
- def self.configure
63
- yield config
87
+ constant = Object
88
+ names.each do |name|
89
+ args = Module.method(:const_get).arity != 1 ? [false] : []
90
+
91
+ if constant.const_defined?(name, *args)
92
+ constant = constant.const_get(name)
93
+ else
94
+ constant = constant.const_missing(name)
95
+ end
96
+ end
97
+ constant
64
98
  end
65
99
 
100
+ extend ::Forwardable
101
+
66
102
  # Accepts:
67
103
  # 1. A 'hostname:port' String
68
104
  # 2. A 'hostname:port:db' String (to select the Redis db)
@@ -116,6 +152,19 @@ module Resque
116
152
  # Set or retrieve the current logger object
117
153
  attr_accessor :logger
118
154
 
155
+ DEFAULT_HEARTBEAT_INTERVAL = 60
156
+ DEFAULT_PRUNE_INTERVAL = DEFAULT_HEARTBEAT_INTERVAL * 5
157
+
158
+ attr_writer :heartbeat_interval
159
+ def heartbeat_interval
160
+ @heartbeat_interval || DEFAULT_HEARTBEAT_INTERVAL
161
+ end
162
+
163
+ attr_writer :prune_interval
164
+ def prune_interval
165
+ @prune_interval || DEFAULT_PRUNE_INTERVAL
166
+ end
167
+
119
168
  # The `before_first_fork` hook will be run in the **parent** process
120
169
  # only once, before forking to run the first job. Be careful- any
121
170
  # changes you make will be permanent for the lifespan of the
@@ -168,8 +217,10 @@ module Resque
168
217
  block ? register_hook(:before_pause, block) : hooks(:before_pause)
169
218
  end
170
219
 
171
- # Set the after_pause proc.
172
- attr_writer :before_pause
220
+ # Register a before_pause proc.
221
+ def before_pause=(block)
222
+ register_hook(:before_pause, block)
223
+ end
173
224
 
174
225
  # The `after_pause` hook will be run in the parent process after the
175
226
  # worker has paused (via SIGCONT).
@@ -177,8 +228,10 @@ module Resque
177
228
  block ? register_hook(:after_pause, block) : hooks(:after_pause)
178
229
  end
179
230
 
180
- # Set the after_continue proc.
181
- attr_writer :after_pause
231
+ # Register an after_pause proc.
232
+ def after_pause=(block)
233
+ register_hook(:after_pause, block)
234
+ end
182
235
 
183
236
  def to_s
184
237
  "Resque Client connected to #{redis_id}"
@@ -211,9 +264,10 @@ module Resque
211
264
  #
212
265
  # Returns nothing
213
266
  def push(queue, item)
267
+ encoded = encode(item)
214
268
  redis.pipelined do
215
269
  watch_queue(queue)
216
- redis.rpush "queue:#{queue}", encode(item)
270
+ redis.rpush "queue:#{queue}", encoded
217
271
  end
218
272
  end
219
273
 
@@ -391,7 +445,7 @@ module Resque
391
445
  queue ||= queue_from_class(klass)
392
446
 
393
447
  if !queue
394
- raise NoQueueError.new("Jobs must be placed onto a queue.")
448
+ raise NoQueueError.new("Jobs must be placed onto a queue. No queue could be inferred for class #{klass}")
395
449
  end
396
450
 
397
451
  if klass.to_s.empty?
@@ -428,7 +482,7 @@ module Resque
428
482
  # Returns a hash, similar to redis-rb's #info, of interesting stats.
429
483
  def info
430
484
  return {
431
- :pending => queues.inject(0) { |m,k| m + size(k) },
485
+ :pending => queue_sizes.inject(0) { |sum, (queue_name, queue_size)| sum + queue_size },
432
486
  :processed => Stat[:processed],
433
487
  :queues => queues.size,
434
488
  :workers => workers.size.to_i,
@@ -447,6 +501,47 @@ module Resque
447
501
  end
448
502
  end
449
503
 
504
+ # Returns a hash, mapping queue names to queue sizes
505
+ def queue_sizes
506
+ queue_names = queues
507
+
508
+ sizes = redis.pipelined do
509
+ queue_names.each do |name|
510
+ redis.llen("queue:#{name}")
511
+ end
512
+ end
513
+
514
+ Hash[queue_names.zip(sizes)]
515
+ end
516
+
517
+ # Returns a hash, mapping queue names to (up to `sample_size`) samples of jobs in that queue
518
+ def sample_queues(sample_size = 1000)
519
+ queue_names = queues
520
+
521
+ samples = redis.pipelined do
522
+ queue_names.each do |name|
523
+ key = "queue:#{name}"
524
+ redis.llen(key)
525
+ redis.lrange(key, 0, sample_size - 1)
526
+ end
527
+ end
528
+
529
+ hash = {}
530
+
531
+ queue_names.zip(samples.each_slice(2).to_a) do |queue_name, (queue_size, serialized_samples)|
532
+ samples = serialized_samples.map do |serialized_sample|
533
+ Job.decode(serialized_sample)
534
+ end
535
+
536
+ hash[queue_name] = {
537
+ :size => queue_size,
538
+ :samples => samples
539
+ }
540
+ end
541
+
542
+ hash
543
+ end
544
+
450
545
  private
451
546
 
452
547
  # Register a new proc as a hook. If the block is nil this is the
@@ -468,6 +563,11 @@ module Resque
468
563
  @hooks && @hooks[name] = []
469
564
  end
470
565
 
566
+ # Retrieve all hooks
567
+ def hooks
568
+ @hooks || {}
569
+ end
570
+
471
571
  # Retrieve all hooks of a given name.
472
572
  def hooks(name)
473
573
  (@hooks && @hooks[name]) || []
@@ -7,6 +7,7 @@ module Resque
7
7
 
8
8
  # Raised when a worker was killed while processing a job.
9
9
  class DirtyExit < RuntimeError; end
10
+ class PruneDeadWorkerDirtyExit < DirtyExit; end
10
11
 
11
12
  # Raised when child process is TERM'd so job can rescue this to do shutdown work.
12
13
  class TermException < SignalException; end
@@ -90,24 +90,30 @@ module Resque
90
90
  backend.clear(queue)
91
91
  end
92
92
 
93
- def self.requeue(id)
94
- backend.requeue(id)
93
+ def self.requeue(id, queue = nil)
94
+ backend.requeue(id, queue)
95
95
  end
96
96
 
97
- def self.remove(id)
98
- backend.remove(id)
97
+ def self.remove(id, queue = nil)
98
+ backend.remove(id, queue)
99
99
  end
100
-
100
+
101
101
  # Requeues all failed jobs in a specific queue.
102
102
  # Queue name should be a string.
103
103
  def self.requeue_queue(queue)
104
104
  backend.requeue_queue(queue)
105
105
  end
106
106
 
107
+ # Requeues all failed jobs
108
+ def self.requeue_all
109
+ backend.requeue_all
110
+ end
111
+
107
112
  # Removes all failed jobs in a specific queue.
108
113
  # Queue name should be a string.
109
114
  def self.remove_queue(queue)
110
115
  backend.remove_queue(queue)
111
116
  end
117
+
112
118
  end
113
119
  end