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.
- checksums.yaml +7 -0
- data/HISTORY.md +29 -16
- data/README.markdown +60 -6
- data/Rakefile +4 -17
- data/bin/resque-web +4 -0
- data/lib/resque.rb +116 -16
- data/lib/resque/errors.rb +1 -0
- data/lib/resque/failure.rb +11 -5
- data/lib/resque/failure/multiple.rb +6 -1
- data/lib/resque/failure/redis.rb +13 -4
- data/lib/resque/failure/redis_multi_queue.rb +14 -6
- data/lib/resque/helpers.rb +5 -64
- data/lib/resque/job.rb +25 -79
- data/lib/resque/logging.rb +1 -1
- data/lib/resque/plugin.rb +22 -10
- data/lib/resque/server.rb +35 -7
- data/lib/resque/server/helpers.rb +1 -1
- data/lib/resque/server/views/failed.erb +1 -1
- data/lib/resque/server/views/failed_job.erb +3 -3
- data/lib/resque/server/views/failed_queues_overview.erb +3 -3
- data/lib/resque/server/views/workers.erb +2 -0
- data/lib/resque/server/views/working.erb +4 -5
- data/lib/resque/tasks.rb +7 -25
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +1 -0
- data/lib/resque/version.rb +1 -1
- data/lib/resque/worker.rb +225 -116
- metadata +68 -90
- data/test/airbrake_test.rb +0 -27
- data/test/dump.rdb +0 -0
- data/test/failure_base_test.rb +0 -15
- data/test/job_hooks_test.rb +0 -464
- data/test/job_plugins_test.rb +0 -230
- data/test/logging_test.rb +0 -24
- data/test/plugin_test.rb +0 -116
- data/test/redis-test-cluster.conf +0 -115
- data/test/redis-test.conf +0 -115
- data/test/resque-web_test.rb +0 -59
- data/test/resque_failure_redis_test.rb +0 -19
- data/test/resque_hook_test.rb +0 -165
- data/test/resque_test.rb +0 -278
- data/test/test_helper.rb +0 -198
- data/test/worker_test.rb +0 -1015
checksums.yaml
ADDED
@@ -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.
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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 (
|
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)
|
data/README.markdown
CHANGED
@@ -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
|
-
|
434
|
-
|
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://
|
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
|
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
|
data/bin/resque-web
CHANGED
@@ -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
|
data/lib/resque.rb
CHANGED
@@ -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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
63
|
-
|
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
|
-
#
|
172
|
-
|
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
|
-
#
|
181
|
-
|
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}",
|
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 =>
|
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]) || []
|
data/lib/resque/errors.rb
CHANGED
@@ -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
|
data/lib/resque/failure.rb
CHANGED
@@ -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
|