resque_sqs 1.25.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/HISTORY.md +467 -0
- data/LICENSE +20 -0
- data/README.markdown +866 -0
- data/Rakefile +70 -0
- data/bin/resque-sqs +81 -0
- data/bin/resque-sqs-web +27 -0
- data/lib/resque_sqs/errors.rb +13 -0
- data/lib/resque_sqs/failure/airbrake.rb +33 -0
- data/lib/resque_sqs/failure/base.rb +73 -0
- data/lib/resque_sqs/failure/multiple.rb +59 -0
- data/lib/resque_sqs/failure/redis.rb +108 -0
- data/lib/resque_sqs/failure/redis_multi_queue.rb +89 -0
- data/lib/resque_sqs/failure.rb +113 -0
- data/lib/resque_sqs/helpers.rb +107 -0
- data/lib/resque_sqs/job.rb +346 -0
- data/lib/resque_sqs/log_formatters/quiet_formatter.rb +7 -0
- data/lib/resque_sqs/log_formatters/verbose_formatter.rb +7 -0
- data/lib/resque_sqs/log_formatters/very_verbose_formatter.rb +8 -0
- data/lib/resque_sqs/logging.rb +18 -0
- data/lib/resque_sqs/plugin.rb +66 -0
- data/lib/resque_sqs/server/helpers.rb +52 -0
- data/lib/resque_sqs/server/public/favicon.ico +0 -0
- data/lib/resque_sqs/server/public/idle.png +0 -0
- data/lib/resque_sqs/server/public/jquery-1.3.2.min.js +19 -0
- data/lib/resque_sqs/server/public/jquery.relatize_date.js +95 -0
- data/lib/resque_sqs/server/public/poll.png +0 -0
- data/lib/resque_sqs/server/public/ranger.js +78 -0
- data/lib/resque_sqs/server/public/reset.css +44 -0
- data/lib/resque_sqs/server/public/style.css +91 -0
- data/lib/resque_sqs/server/public/working.png +0 -0
- data/lib/resque_sqs/server/test_helper.rb +19 -0
- data/lib/resque_sqs/server/views/error.erb +1 -0
- data/lib/resque_sqs/server/views/failed.erb +29 -0
- data/lib/resque_sqs/server/views/failed_job.erb +50 -0
- data/lib/resque_sqs/server/views/failed_queues_overview.erb +24 -0
- data/lib/resque_sqs/server/views/key_sets.erb +19 -0
- data/lib/resque_sqs/server/views/key_string.erb +11 -0
- data/lib/resque_sqs/server/views/layout.erb +44 -0
- data/lib/resque_sqs/server/views/next_more.erb +22 -0
- data/lib/resque_sqs/server/views/overview.erb +4 -0
- data/lib/resque_sqs/server/views/queues.erb +58 -0
- data/lib/resque_sqs/server/views/stats.erb +62 -0
- data/lib/resque_sqs/server/views/workers.erb +109 -0
- data/lib/resque_sqs/server/views/working.erb +72 -0
- data/lib/resque_sqs/server.rb +271 -0
- data/lib/resque_sqs/stat.rb +57 -0
- data/lib/resque_sqs/tasks.rb +83 -0
- data/lib/resque_sqs/vendor/utf8_util/utf8_util_18.rb +91 -0
- data/lib/resque_sqs/vendor/utf8_util/utf8_util_19.rb +5 -0
- data/lib/resque_sqs/vendor/utf8_util.rb +20 -0
- data/lib/resque_sqs/version.rb +3 -0
- data/lib/resque_sqs/worker.rb +779 -0
- data/lib/resque_sqs.rb +479 -0
- data/lib/tasks/redis_sqs.rake +161 -0
- data/lib/tasks/resque_sqs.rake +2 -0
- data/test/airbrake_test.rb +27 -0
- data/test/failure_base_test.rb +15 -0
- data/test/job_hooks_test.rb +465 -0
- data/test/job_plugins_test.rb +230 -0
- data/test/logging_test.rb +24 -0
- data/test/plugin_test.rb +116 -0
- data/test/redis-test-cluster.conf +115 -0
- data/test/redis-test.conf +115 -0
- data/test/resque-web_test.rb +59 -0
- data/test/resque_failure_redis_test.rb +19 -0
- data/test/resque_hook_test.rb +165 -0
- data/test/resque_test.rb +278 -0
- data/test/stdout +42 -0
- data/test/test_helper.rb +228 -0
- data/test/worker_test.rb +1080 -0
- metadata +202 -0
@@ -0,0 +1,107 @@
|
|
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 ResqueSqs
|
12
|
+
# Methods used by various classes in ResqueSqs.
|
13
|
+
module Helpers
|
14
|
+
def self.extended(parent_class)
|
15
|
+
warn("ResqueSqs::Helpers will be gone with no replacement in Resque 2.0.0.")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.included(parent_class)
|
19
|
+
warn("ResqueSqs::Helpers will be gone with no replacement in Resque 2.0.0.")
|
20
|
+
end
|
21
|
+
|
22
|
+
class DecodeException < StandardError; end
|
23
|
+
|
24
|
+
# Direct access to the Redis instance.
|
25
|
+
def redis
|
26
|
+
# No infinite recursions, please.
|
27
|
+
# Some external libraries depend on ResqueSqs::Helpers being mixed into
|
28
|
+
# Resque, but this method causes recursions. If we have a super method,
|
29
|
+
# assume it is canonical. (see #1150)
|
30
|
+
return super if defined?(super)
|
31
|
+
|
32
|
+
ResqueSqs.redis
|
33
|
+
end
|
34
|
+
|
35
|
+
# Given a Ruby object, returns a string suitable for storage in a
|
36
|
+
# queue.
|
37
|
+
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
|
43
|
+
end
|
44
|
+
|
45
|
+
# Given a string, returns a Ruby object.
|
46
|
+
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
|
58
|
+
end
|
59
|
+
|
60
|
+
# Given a word with dashes, returns a camel cased version of it.
|
61
|
+
#
|
62
|
+
# classify('job-name') # => 'JobName'
|
63
|
+
def classify(dashed_word)
|
64
|
+
dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
|
65
|
+
end
|
66
|
+
|
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.
|
84
|
+
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
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,346 @@
|
|
1
|
+
module ResqueSqs
|
2
|
+
# A ResqueSqs::Job represents a unit of work. Each job lives on a
|
3
|
+
# single queue and has an associated payload object. The payload
|
4
|
+
# is a hash with two attributes: `class` and `args`. The `class` is
|
5
|
+
# the name of the Ruby class which should be used to run the
|
6
|
+
# job. The `args` are an array of arguments which should be passed
|
7
|
+
# to the Ruby class's `perform` class-level method.
|
8
|
+
#
|
9
|
+
# You can manually run a job using this code:
|
10
|
+
#
|
11
|
+
# job = ResqueSqs::Job.reserve(:high)
|
12
|
+
# klass = ResqueSqs::Job.constantize(job.payload['class'])
|
13
|
+
# klass.perform(*job.payload['args'])
|
14
|
+
class Job
|
15
|
+
def redis
|
16
|
+
ResqueSqs.redis
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.redis
|
20
|
+
ResqueSqs.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
|
119
|
+
|
120
|
+
# Raise ResqueSqs::Job::DontPerform from a before_perform hook to
|
121
|
+
# abort the job.
|
122
|
+
DontPerform = Class.new(StandardError)
|
123
|
+
|
124
|
+
# The worker object which is currently processing this job.
|
125
|
+
attr_accessor :worker
|
126
|
+
|
127
|
+
# The name of the queue from which this job was pulled (or is to be
|
128
|
+
# placed)
|
129
|
+
attr_reader :queue
|
130
|
+
|
131
|
+
# This job's associated payload object.
|
132
|
+
attr_reader :payload
|
133
|
+
|
134
|
+
def initialize(queue, payload)
|
135
|
+
@queue = queue
|
136
|
+
@payload = payload
|
137
|
+
@failure_hooks_ran = false
|
138
|
+
end
|
139
|
+
|
140
|
+
# Creates a job by placing it on a queue. Expects a string queue
|
141
|
+
# name, a string class name, and an optional array of arguments to
|
142
|
+
# pass to the class' `perform` method.
|
143
|
+
#
|
144
|
+
# Raises an exception if no queue or class is given.
|
145
|
+
def self.create(queue, klass, *args)
|
146
|
+
ResqueSqs.validate(klass, queue)
|
147
|
+
|
148
|
+
if ResqueSqs.inline?
|
149
|
+
# Instantiating a ResqueSqs::Job and calling perform on it so callbacks run
|
150
|
+
# decode(encode(args)) to ensure that args are normalized in the same manner as a non-inline job
|
151
|
+
new(:inline, {'class' => klass, 'args' => decode(encode(args))}).perform
|
152
|
+
else
|
153
|
+
ResqueSqs.push(queue, :class => klass.to_s, :args => args)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Removes a job from a queue. Expects a string queue name, a
|
158
|
+
# string class name, and, optionally, args.
|
159
|
+
#
|
160
|
+
# Returns the number of jobs destroyed.
|
161
|
+
#
|
162
|
+
# If no args are provided, it will remove all jobs of the class
|
163
|
+
# provided.
|
164
|
+
#
|
165
|
+
# That is, for these two jobs:
|
166
|
+
#
|
167
|
+
# { 'class' => 'UpdateGraph', 'args' => ['defunkt'] }
|
168
|
+
# { 'class' => 'UpdateGraph', 'args' => ['mojombo'] }
|
169
|
+
#
|
170
|
+
# The following call will remove both:
|
171
|
+
#
|
172
|
+
# ResqueSqs::Job.destroy(queue, 'UpdateGraph')
|
173
|
+
#
|
174
|
+
# Whereas specifying args will only remove the 2nd job:
|
175
|
+
#
|
176
|
+
# ResqueSqs::Job.destroy(queue, 'UpdateGraph', 'mojombo')
|
177
|
+
#
|
178
|
+
# This method can be potentially very slow and memory intensive,
|
179
|
+
# depending on the size of your queue, as it loads all jobs into
|
180
|
+
# a Ruby array before processing.
|
181
|
+
def self.destroy(queue, klass, *args)
|
182
|
+
klass = klass.to_s
|
183
|
+
queue = "queue:#{queue}"
|
184
|
+
destroyed = 0
|
185
|
+
|
186
|
+
if args.empty?
|
187
|
+
redis.lrange(queue, 0, -1).each do |string|
|
188
|
+
if decode(string)['class'] == klass
|
189
|
+
destroyed += redis.lrem(queue, 0, string).to_i
|
190
|
+
end
|
191
|
+
end
|
192
|
+
else
|
193
|
+
destroyed += redis.lrem(queue, 0, encode(:class => klass, :args => args))
|
194
|
+
end
|
195
|
+
|
196
|
+
destroyed
|
197
|
+
end
|
198
|
+
|
199
|
+
# Given a string queue name, returns an instance of ResqueSqs::Job
|
200
|
+
# if any jobs are available. If not, returns nil.
|
201
|
+
def self.reserve(queue)
|
202
|
+
return unless payload = ResqueSqs.pop(queue)
|
203
|
+
new(queue, payload)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Attempts to perform the work represented by this job instance.
|
207
|
+
# Calls #perform on the class given in the payload with the
|
208
|
+
# arguments given in the payload.
|
209
|
+
def perform
|
210
|
+
job = payload_class
|
211
|
+
job_args = args || []
|
212
|
+
job_was_performed = false
|
213
|
+
|
214
|
+
begin
|
215
|
+
# Execute before_perform hook. Abort the job gracefully if
|
216
|
+
# ResqueSqs::DontPerform is raised.
|
217
|
+
begin
|
218
|
+
before_hooks.each do |hook|
|
219
|
+
job.send(hook, *job_args)
|
220
|
+
end
|
221
|
+
rescue DontPerform
|
222
|
+
return false
|
223
|
+
end
|
224
|
+
|
225
|
+
# Execute the job. Do it in an around_perform hook if available.
|
226
|
+
if around_hooks.empty?
|
227
|
+
job.perform(*job_args)
|
228
|
+
job_was_performed = true
|
229
|
+
else
|
230
|
+
# We want to nest all around_perform plugins, with the last one
|
231
|
+
# finally calling perform
|
232
|
+
stack = around_hooks.reverse.inject(nil) do |last_hook, hook|
|
233
|
+
if last_hook
|
234
|
+
lambda do
|
235
|
+
job.send(hook, *job_args) { last_hook.call }
|
236
|
+
end
|
237
|
+
else
|
238
|
+
lambda do
|
239
|
+
job.send(hook, *job_args) do
|
240
|
+
result = job.perform(*job_args)
|
241
|
+
job_was_performed = true
|
242
|
+
result
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
stack.call
|
248
|
+
end
|
249
|
+
|
250
|
+
# Execute after_perform hook
|
251
|
+
after_hooks.each do |hook|
|
252
|
+
job.send(hook, *job_args)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Return true if the job was performed
|
256
|
+
return job_was_performed
|
257
|
+
|
258
|
+
# If an exception occurs during the job execution, look for an
|
259
|
+
# on_failure hook then re-raise.
|
260
|
+
rescue Object => e
|
261
|
+
run_failure_hooks(e)
|
262
|
+
raise e
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Returns the actual class constant represented in this job's payload.
|
267
|
+
def payload_class
|
268
|
+
@payload_class ||= constantize(@payload['class'])
|
269
|
+
end
|
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
|
+
|
284
|
+
# Returns an array of args represented in this job's payload.
|
285
|
+
def args
|
286
|
+
@payload['args']
|
287
|
+
end
|
288
|
+
|
289
|
+
# Given an exception object, hands off the needed parameters to
|
290
|
+
# the Failure module.
|
291
|
+
def fail(exception)
|
292
|
+
run_failure_hooks(exception)
|
293
|
+
Failure.create \
|
294
|
+
:payload => payload,
|
295
|
+
:exception => exception,
|
296
|
+
:worker => worker,
|
297
|
+
:queue => queue
|
298
|
+
end
|
299
|
+
|
300
|
+
# Creates an identical job, essentially placing this job back on
|
301
|
+
# the queue.
|
302
|
+
def recreate
|
303
|
+
self.class.create(queue, payload_class, *args)
|
304
|
+
end
|
305
|
+
|
306
|
+
# String representation
|
307
|
+
def inspect
|
308
|
+
obj = @payload
|
309
|
+
"(Job{%s} | %s | %s)" % [ @queue, obj['class'], obj['args'].inspect ]
|
310
|
+
end
|
311
|
+
|
312
|
+
# Equality
|
313
|
+
def ==(other)
|
314
|
+
queue == other.queue &&
|
315
|
+
payload_class == other.payload_class &&
|
316
|
+
args == other.args
|
317
|
+
end
|
318
|
+
|
319
|
+
def before_hooks
|
320
|
+
@before_hooks ||= Plugin.before_hooks(payload_class)
|
321
|
+
end
|
322
|
+
|
323
|
+
def around_hooks
|
324
|
+
@around_hooks ||= Plugin.around_hooks(payload_class)
|
325
|
+
end
|
326
|
+
|
327
|
+
def after_hooks
|
328
|
+
@after_hooks ||= Plugin.after_hooks(payload_class)
|
329
|
+
end
|
330
|
+
|
331
|
+
def failure_hooks
|
332
|
+
@failure_hooks ||= Plugin.failure_hooks(payload_class)
|
333
|
+
end
|
334
|
+
|
335
|
+
def run_failure_hooks(exception)
|
336
|
+
begin
|
337
|
+
job_args = args || []
|
338
|
+
if has_payload_class?
|
339
|
+
failure_hooks.each { |hook| payload_class.send(hook, exception, *job_args) } unless @failure_hooks_ran
|
340
|
+
end
|
341
|
+
ensure
|
342
|
+
@failure_hooks_ran = true
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ResqueSqs
|
2
|
+
# Include this module in classes you wish to have logging facilities
|
3
|
+
module Logging
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# Thunk to the logger's own log method (if configured)
|
7
|
+
def self.log(severity, message)
|
8
|
+
ResqueSqs.logger.__send__(severity, message) if ResqueSqs.logger
|
9
|
+
end
|
10
|
+
|
11
|
+
# Log level aliases
|
12
|
+
def debug(message); Logging.log :debug, message; end
|
13
|
+
def info(message); Logging.log :info, message; end
|
14
|
+
def warn(message); Logging.log :warn, message; end
|
15
|
+
def error(message); Logging.log :error, message; end
|
16
|
+
def fatal(message); Logging.log :fatal, message; end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module ResqueSqs
|
2
|
+
module Plugin
|
3
|
+
extend self
|
4
|
+
|
5
|
+
LintError = Class.new(RuntimeError)
|
6
|
+
|
7
|
+
# Ensure that your plugin conforms to good hook naming conventions.
|
8
|
+
#
|
9
|
+
# ResqueSqs::Plugin.lint(MyResquePlugin)
|
10
|
+
def lint(plugin)
|
11
|
+
hooks = before_hooks(plugin) + around_hooks(plugin) + after_hooks(plugin)
|
12
|
+
|
13
|
+
hooks.each do |hook|
|
14
|
+
if hook =~ /perform$/
|
15
|
+
raise LintError, "#{plugin}.#{hook} is not namespaced"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
failure_hooks(plugin).each do |hook|
|
20
|
+
if hook =~ /failure$/
|
21
|
+
raise LintError, "#{plugin}.#{hook} is not namespaced"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Given an object, returns a list `before_perform` hook names.
|
27
|
+
def before_hooks(job)
|
28
|
+
job.methods.grep(/^before_perform/).sort
|
29
|
+
end
|
30
|
+
|
31
|
+
# Given an object, returns a list `around_perform` hook names.
|
32
|
+
def around_hooks(job)
|
33
|
+
job.methods.grep(/^around_perform/).sort
|
34
|
+
end
|
35
|
+
|
36
|
+
# Given an object, returns a list `after_perform` hook names.
|
37
|
+
def after_hooks(job)
|
38
|
+
job.methods.grep(/^after_perform/).sort
|
39
|
+
end
|
40
|
+
|
41
|
+
# Given an object, returns a list `on_failure` hook names.
|
42
|
+
def failure_hooks(job)
|
43
|
+
job.methods.grep(/^on_failure/).sort
|
44
|
+
end
|
45
|
+
|
46
|
+
# Given an object, returns a list `after_enqueue` hook names.
|
47
|
+
def after_enqueue_hooks(job)
|
48
|
+
job.methods.grep(/^after_enqueue/).sort
|
49
|
+
end
|
50
|
+
|
51
|
+
# Given an object, returns a list `before_enqueue` hook names.
|
52
|
+
def before_enqueue_hooks(job)
|
53
|
+
job.methods.grep(/^before_enqueue/).sort
|
54
|
+
end
|
55
|
+
|
56
|
+
# Given an object, returns a list `after_dequeue` hook names.
|
57
|
+
def after_dequeue_hooks(job)
|
58
|
+
job.methods.grep(/^after_dequeue/).sort
|
59
|
+
end
|
60
|
+
|
61
|
+
# Given an object, returns a list `before_dequeue` hook names.
|
62
|
+
def before_dequeue_hooks(job)
|
63
|
+
job.methods.grep(/^before_dequeue/).sort
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
ResqueSqs::Server.helpers do
|
2
|
+
####################
|
3
|
+
#failed.erb helpers#
|
4
|
+
####################
|
5
|
+
|
6
|
+
def failed_date_format
|
7
|
+
"%Y/%m/%d %T %z"
|
8
|
+
end
|
9
|
+
|
10
|
+
def failed_multiple_queues?
|
11
|
+
return @multiple_failed_queues if defined?(@multiple_failed_queues)
|
12
|
+
@multiple_failed_queues = ResqueSqs::Failure.queues.size > 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def failed_size
|
16
|
+
@failed_size ||= ResqueSqs::Failure.count(params[:queue], params[:class])
|
17
|
+
end
|
18
|
+
|
19
|
+
def failed_per_page
|
20
|
+
@failed_per_page = if params[:class]
|
21
|
+
failed_size
|
22
|
+
else
|
23
|
+
20
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def failed_start_at
|
28
|
+
params[:start].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def failed_end_at
|
32
|
+
if failed_start_at + failed_per_page > failed_size
|
33
|
+
failed_size
|
34
|
+
else
|
35
|
+
failed_start_at + failed_per_page
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def failed_order
|
40
|
+
params[:order] || 'desc'
|
41
|
+
end
|
42
|
+
|
43
|
+
def failed_class_counts(queue = params[:queue])
|
44
|
+
classes = Hash.new(0)
|
45
|
+
ResqueSqs::Failure.each(0, ResqueSqs::Failure.count(queue), queue) do |_, item|
|
46
|
+
class_name = item['payload']['class'] if item['payload']
|
47
|
+
class_name ||= "nil"
|
48
|
+
classes[class_name] += 1
|
49
|
+
end
|
50
|
+
classes
|
51
|
+
end
|
52
|
+
end
|
Binary file
|
Binary file
|