resque-master 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/HISTORY.md +488 -0
- data/LICENSE +20 -0
- data/README.markdown +920 -0
- data/Rakefile +57 -0
- data/bin/resque +81 -0
- data/bin/resque-web +31 -0
- data/lib/resque.rb +578 -0
- data/lib/resque/data_store.rb +326 -0
- data/lib/resque/errors.rb +21 -0
- data/lib/resque/failure.rb +119 -0
- data/lib/resque/failure/airbrake.rb +33 -0
- data/lib/resque/failure/base.rb +73 -0
- data/lib/resque/failure/multiple.rb +68 -0
- data/lib/resque/failure/redis.rb +128 -0
- data/lib/resque/failure/redis_multi_queue.rb +104 -0
- data/lib/resque/helpers.rb +48 -0
- data/lib/resque/job.rb +296 -0
- data/lib/resque/log_formatters/quiet_formatter.rb +7 -0
- data/lib/resque/log_formatters/verbose_formatter.rb +7 -0
- data/lib/resque/log_formatters/very_verbose_formatter.rb +8 -0
- data/lib/resque/logging.rb +18 -0
- data/lib/resque/plugin.rb +78 -0
- data/lib/resque/server.rb +299 -0
- data/lib/resque/server/helpers.rb +64 -0
- data/lib/resque/server/public/favicon.ico +0 -0
- data/lib/resque/server/public/idle.png +0 -0
- data/lib/resque/server/public/jquery-1.12.4.min.js +5 -0
- data/lib/resque/server/public/jquery.relatize_date.js +95 -0
- data/lib/resque/server/public/poll.png +0 -0
- data/lib/resque/server/public/ranger.js +78 -0
- data/lib/resque/server/public/reset.css +44 -0
- data/lib/resque/server/public/style.css +91 -0
- data/lib/resque/server/public/working.png +0 -0
- data/lib/resque/server/test_helper.rb +19 -0
- data/lib/resque/server/views/error.erb +1 -0
- data/lib/resque/server/views/failed.erb +29 -0
- data/lib/resque/server/views/failed_job.erb +50 -0
- data/lib/resque/server/views/failed_queues_overview.erb +24 -0
- data/lib/resque/server/views/key_sets.erb +17 -0
- data/lib/resque/server/views/key_string.erb +11 -0
- data/lib/resque/server/views/layout.erb +44 -0
- data/lib/resque/server/views/next_more.erb +22 -0
- data/lib/resque/server/views/overview.erb +4 -0
- data/lib/resque/server/views/queues.erb +58 -0
- data/lib/resque/server/views/stats.erb +62 -0
- data/lib/resque/server/views/workers.erb +111 -0
- data/lib/resque/server/views/working.erb +72 -0
- data/lib/resque/stat.rb +58 -0
- data/lib/resque/tasks.rb +72 -0
- data/lib/resque/thread_signal.rb +45 -0
- data/lib/resque/vendor/utf8_util.rb +26 -0
- data/lib/resque/vendor/utf8_util/utf8_util_18.rb +91 -0
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +6 -0
- data/lib/resque/version.rb +5 -0
- data/lib/resque/worker.rb +891 -0
- data/lib/tasks/redis.rake +161 -0
- data/lib/tasks/resque.rake +2 -0
- metadata +177 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
begin
|
2
|
+
require 'airbrake'
|
3
|
+
rescue LoadError
|
4
|
+
raise "Can't find 'airbrake' gem. Please add it to your Gemfile or install it."
|
5
|
+
end
|
6
|
+
|
7
|
+
module Resque
|
8
|
+
module Failure
|
9
|
+
class Airbrake < Base
|
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
|
22
|
+
|
23
|
+
def save
|
24
|
+
::Airbrake.notify(exception,
|
25
|
+
:parameters => {
|
26
|
+
:payload_class => payload['class'].to_s,
|
27
|
+
:payload_args => payload['args'].inspect
|
28
|
+
}
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Resque
|
2
|
+
module Failure
|
3
|
+
# All Failure classes are expected to subclass Base.
|
4
|
+
#
|
5
|
+
# When a job fails, a new instance of your Failure backend is created
|
6
|
+
# and #save is called.
|
7
|
+
class Base
|
8
|
+
# The exception object raised by the failed job
|
9
|
+
attr_accessor :exception
|
10
|
+
|
11
|
+
# The worker object who detected the failure
|
12
|
+
attr_accessor :worker
|
13
|
+
|
14
|
+
# The string name of the queue from which the failed job was pulled
|
15
|
+
attr_accessor :queue
|
16
|
+
|
17
|
+
# The payload object associated with the failed job
|
18
|
+
attr_accessor :payload
|
19
|
+
|
20
|
+
def initialize(exception, worker, queue, payload)
|
21
|
+
@exception = exception
|
22
|
+
@worker = worker
|
23
|
+
@queue = queue
|
24
|
+
@payload = payload
|
25
|
+
end
|
26
|
+
|
27
|
+
# When a job fails, a new instance of your Failure backend is created
|
28
|
+
# and #save is called.
|
29
|
+
#
|
30
|
+
# This is where you POST or PUT or whatever to your Failure service.
|
31
|
+
def save
|
32
|
+
end
|
33
|
+
|
34
|
+
# The number of failures.
|
35
|
+
def self.count(queue = nil, class_name = nil)
|
36
|
+
0
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns an array of all available failure queues
|
40
|
+
def self.queues
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a paginated array of failure objects.
|
45
|
+
def self.all(offset = 0, limit = 1, queue = nil)
|
46
|
+
[]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Iterate across failed objects
|
50
|
+
def self.each(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
# A URL where someone can go to view failures.
|
54
|
+
def self.url
|
55
|
+
end
|
56
|
+
|
57
|
+
# Clear all failure objects
|
58
|
+
def self.clear(*args)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.requeue(*args)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.remove(*args)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Logging!
|
68
|
+
def log(message)
|
69
|
+
@worker.log(message)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Resque
|
2
|
+
module Failure
|
3
|
+
# A Failure backend that uses multiple backends
|
4
|
+
# delegates all queries to the first backend
|
5
|
+
class Multiple < Base
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :classes
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.configure
|
12
|
+
yield self
|
13
|
+
Resque::Failure.backend = self
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(*args)
|
17
|
+
super
|
18
|
+
@backends = self.class.classes.map {|klass| klass.new(*args)}
|
19
|
+
end
|
20
|
+
|
21
|
+
def save
|
22
|
+
@backends.each(&:save)
|
23
|
+
end
|
24
|
+
|
25
|
+
# The number of failures.
|
26
|
+
def self.count(*args)
|
27
|
+
classes.first.count(*args)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns an array of all available failure queues
|
31
|
+
def self.queues
|
32
|
+
classes.first.queues
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns a paginated array of failure objects.
|
36
|
+
def self.all(*args)
|
37
|
+
classes.first.all(*args)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Iterate across failed objects
|
41
|
+
def self.each(*args, &block)
|
42
|
+
classes.first.each(*args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# A URL where someone can go to view failures.
|
46
|
+
def self.url
|
47
|
+
classes.first.url
|
48
|
+
end
|
49
|
+
|
50
|
+
# Clear all failure objects
|
51
|
+
def self.clear(*args)
|
52
|
+
classes.first.clear(*args)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.requeue(*args)
|
56
|
+
classes.first.requeue(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.requeue_all
|
60
|
+
classes.first.requeue_all
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.remove(index, queue)
|
64
|
+
classes.each { |klass| klass.remove(index) }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Resque
|
2
|
+
module Failure
|
3
|
+
# A Failure backend that stores exceptions in Redis. Very simple but
|
4
|
+
# works out of the box, along with support in the Resque web app.
|
5
|
+
class Redis < Base
|
6
|
+
|
7
|
+
def data_store
|
8
|
+
Resque.data_store
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.data_store
|
12
|
+
Resque.data_store
|
13
|
+
end
|
14
|
+
|
15
|
+
def save
|
16
|
+
data = {
|
17
|
+
:failed_at => UTF8Util.clean(Time.now.strftime("%Y/%m/%d %H:%M:%S %Z")),
|
18
|
+
:payload => payload,
|
19
|
+
:exception => exception.class.to_s,
|
20
|
+
:error => UTF8Util.clean(exception.to_s),
|
21
|
+
:backtrace => filter_backtrace(Array(exception.backtrace)),
|
22
|
+
:worker => worker.to_s,
|
23
|
+
:queue => queue
|
24
|
+
}
|
25
|
+
data = Resque.encode(data)
|
26
|
+
data_store.push_to_failed_queue(data)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.count(queue = nil, class_name = nil)
|
30
|
+
check_queue(queue)
|
31
|
+
|
32
|
+
if class_name
|
33
|
+
n = 0
|
34
|
+
each(0, count(queue), queue, class_name) { n += 1 }
|
35
|
+
n
|
36
|
+
else
|
37
|
+
data_store.num_failed
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.queues
|
42
|
+
data_store.failed_queue_names
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.all(offset = 0, limit = 1, queue = nil)
|
46
|
+
check_queue(queue)
|
47
|
+
Resque.list_range(:failed, offset, limit)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
|
51
|
+
if class_name
|
52
|
+
original_limit = limit
|
53
|
+
limit = count
|
54
|
+
end
|
55
|
+
all_items = limit == 1 ? [all(offset,limit,queue)] : Array(all(offset, limit, queue))
|
56
|
+
reversed = false
|
57
|
+
if order.eql? 'desc'
|
58
|
+
all_items.reverse!
|
59
|
+
reversed = true
|
60
|
+
end
|
61
|
+
all_items.each_with_index do |item, i|
|
62
|
+
if !class_name || (item['payload'] && item['payload']['class'] == class_name && (original_limit -= 1) >= 0)
|
63
|
+
if reversed
|
64
|
+
id = (all_items.length - 1) + (offset - i)
|
65
|
+
else
|
66
|
+
id = offset + i
|
67
|
+
end
|
68
|
+
yield id, item
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.clear(queue = nil)
|
74
|
+
check_queue(queue)
|
75
|
+
data_store.clear_failed_queue
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.requeue(id, queue = nil)
|
79
|
+
check_queue(queue)
|
80
|
+
item = all(id)
|
81
|
+
item['retried_at'] = Time.now.strftime("%Y/%m/%d %H:%M:%S")
|
82
|
+
data_store.update_item_in_failed_queue(id,Resque.encode(item))
|
83
|
+
Job.create(item['queue'], item['payload']['class'], *item['payload']['args'])
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.remove(id, queue = nil)
|
87
|
+
check_queue(queue)
|
88
|
+
data_store.remove_from_failed_queue(id, queue)
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.requeue_queue(queue)
|
92
|
+
i = 0
|
93
|
+
while job = all(i)
|
94
|
+
requeue(i) if job['queue'] == queue
|
95
|
+
i += 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.requeue_all
|
100
|
+
count.times do |num|
|
101
|
+
requeue(num)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.remove_queue(queue)
|
106
|
+
i = 0
|
107
|
+
while job = all(i)
|
108
|
+
if job['queue'] == queue
|
109
|
+
# This will remove the failure from the array so do not increment the index.
|
110
|
+
remove(i)
|
111
|
+
else
|
112
|
+
i += 1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.check_queue(queue)
|
118
|
+
raise ArgumentError, "invalid queue: #{queue}" if queue && queue.to_s != "failed"
|
119
|
+
end
|
120
|
+
|
121
|
+
def filter_backtrace(backtrace)
|
122
|
+
index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
|
123
|
+
backtrace.first(index.to_i)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Resque
|
2
|
+
module Failure
|
3
|
+
# A Failure backend that stores exceptions in Redis. Very simple but
|
4
|
+
# works out of the box, along with support in the Resque web app.
|
5
|
+
class RedisMultiQueue < Base
|
6
|
+
|
7
|
+
def data_store
|
8
|
+
Resque.data_store
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.data_store
|
12
|
+
Resque.data_store
|
13
|
+
end
|
14
|
+
|
15
|
+
def save
|
16
|
+
data = {
|
17
|
+
:failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
|
18
|
+
:payload => payload,
|
19
|
+
:exception => exception.class.to_s,
|
20
|
+
:error => UTF8Util.clean(exception.to_s),
|
21
|
+
:backtrace => filter_backtrace(Array(exception.backtrace)),
|
22
|
+
:worker => worker.to_s,
|
23
|
+
:queue => queue
|
24
|
+
}
|
25
|
+
data = Resque.encode(data)
|
26
|
+
data_store.push_to_failed_queue(data,Resque::Failure.failure_queue_name(queue))
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.count(queue = nil, class_name = nil)
|
30
|
+
if queue
|
31
|
+
if class_name
|
32
|
+
n = 0
|
33
|
+
each(0, count(queue), queue, class_name) { n += 1 }
|
34
|
+
n
|
35
|
+
else
|
36
|
+
data_store.num_failed(queue).to_i
|
37
|
+
end
|
38
|
+
else
|
39
|
+
total = 0
|
40
|
+
queues.each { |q| total += count(q) }
|
41
|
+
total
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.all(offset = 0, limit = 1, queue = :failed)
|
46
|
+
Resque.list_range(queue, offset, limit)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.queues
|
50
|
+
data_store.failed_queue_names(:failed_queues)
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
|
54
|
+
items = all(offset, limit, queue)
|
55
|
+
items = [items] unless items.is_a? Array
|
56
|
+
reversed = false
|
57
|
+
if order.eql? 'desc'
|
58
|
+
items.reverse!
|
59
|
+
reversed = true
|
60
|
+
end
|
61
|
+
items.each_with_index do |item, i|
|
62
|
+
if !class_name || (item['payload'] && item['payload']['class'] == class_name)
|
63
|
+
id = reversed ? (items.length - 1) - (offset + i) : offset + i
|
64
|
+
yield id, item
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.clear(queue = :failed)
|
70
|
+
queues = queue ? Array(queue) : self.queues
|
71
|
+
queues.each { |queue| data_store.clear_failed_queue(queue) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.requeue(id, queue = :failed)
|
75
|
+
item = all(id, 1, queue)
|
76
|
+
item['retried_at'] = Time.now.strftime("%Y/%m/%d %H:%M:%S")
|
77
|
+
data_store.update_item_in_failed_queue(id,Resque.encode(item),queue)
|
78
|
+
Job.create(item['queue'], item['payload']['class'], *item['payload']['args'])
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.remove(id, queue = :failed)
|
82
|
+
data_store.remove_from_queue(id,queue)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.requeue_queue(queue)
|
86
|
+
failure_queue = Resque::Failure.failure_queue_name(queue)
|
87
|
+
each(0, count(failure_queue), failure_queue) { |id, _| requeue(id, failure_queue) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.requeue_all
|
91
|
+
queues.each { |queue| requeue_queue(Resque::Failure.job_queue_name(queue)) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.remove_queue(queue)
|
95
|
+
data_store.remove_failed_queue(Resque::Failure.failure_queue_name(queue))
|
96
|
+
end
|
97
|
+
|
98
|
+
def filter_backtrace(backtrace)
|
99
|
+
index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
|
100
|
+
backtrace.first(index.to_i)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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.respond_to?(:adapter)
|
6
|
+
raise "Please install the yajl-ruby or json gem" if MultiJson.adapter.to_s == 'MultiJson::Adapters::OkJson'
|
7
|
+
elsif MultiJson.respond_to?(:engine)
|
8
|
+
raise "Please install the yajl-ruby or json gem" if MultiJson.engine.to_s == 'MultiJson::Engines::OkJson'
|
9
|
+
end
|
10
|
+
|
11
|
+
module Resque
|
12
|
+
# Methods used by various classes in Resque.
|
13
|
+
module Helpers
|
14
|
+
class DecodeException < StandardError; end
|
15
|
+
|
16
|
+
# Direct access to the Redis instance.
|
17
|
+
def redis
|
18
|
+
# No infinite recursions, please.
|
19
|
+
# Some external libraries depend on Resque::Helpers being mixed into
|
20
|
+
# Resque, but this method causes recursions. If we have a super method,
|
21
|
+
# assume it is canonical. (see #1150)
|
22
|
+
return super if defined?(super)
|
23
|
+
|
24
|
+
Resque.redis
|
25
|
+
end
|
26
|
+
|
27
|
+
# Given a Ruby object, returns a string suitable for storage in a
|
28
|
+
# queue.
|
29
|
+
def encode(object)
|
30
|
+
Resque.encode(object)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Given a string, returns a Ruby object.
|
34
|
+
def decode(object)
|
35
|
+
Resque.decode(object)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Given a word with dashes, returns a camel cased version of it.
|
39
|
+
def classify(dashed_word)
|
40
|
+
Resque.classify(dashed_word)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Tries to find a constant with the name specified in the argument string
|
44
|
+
def constantize(camel_cased_word)
|
45
|
+
Resque.constantize(camel_cased_word)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|