resque 1.23.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/HISTORY.md +271 -0
- data/README.markdown +454 -484
- data/Rakefile +4 -17
- data/bin/resque-web +10 -22
- data/lib/resque/data_store.rb +335 -0
- data/lib/resque/errors.rb +15 -1
- data/lib/resque/failure/airbrake.rb +32 -4
- data/lib/resque/failure/base.rb +16 -7
- data/lib/resque/failure/multiple.rb +26 -8
- data/lib/resque/failure/redis.rb +92 -15
- data/lib/resque/failure/redis_multi_queue.rb +104 -0
- data/lib/resque/failure.rb +62 -32
- data/lib/resque/helpers.rb +11 -57
- data/lib/resque/job.rb +79 -12
- 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 +22 -10
- data/lib/resque/railtie.rb +10 -0
- data/lib/resque/server/public/jquery-3.6.0.min.js +2 -0
- data/lib/resque/server/public/jquery.relatize_date.js +4 -4
- data/lib/resque/server/public/main.js +3 -0
- data/lib/resque/server/public/ranger.js +16 -8
- data/lib/resque/server/public/style.css +13 -8
- data/lib/resque/server/views/error.erb +1 -1
- data/lib/resque/server/views/failed.erb +27 -59
- 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/job_class.erb +8 -0
- data/lib/resque/server/views/key_sets.erb +2 -4
- data/lib/resque/server/views/key_string.erb +1 -1
- data/lib/resque/server/views/layout.erb +7 -6
- data/lib/resque/server/views/next_more.erb +22 -10
- data/lib/resque/server/views/processing.erb +2 -0
- data/lib/resque/server/views/queues.erb +22 -13
- data/lib/resque/server/views/stats.erb +5 -5
- data/lib/resque/server/views/workers.erb +4 -4
- data/lib/resque/server/views/working.erb +10 -11
- data/lib/resque/server.rb +51 -108
- data/lib/resque/server_helper.rb +185 -0
- data/lib/resque/stat.rb +19 -7
- data/lib/resque/tasks.rb +26 -25
- data/lib/resque/thread_signal.rb +24 -0
- data/lib/resque/vendor/utf8_util.rb +2 -8
- data/lib/resque/version.rb +1 -1
- data/lib/resque/web_runner.rb +374 -0
- data/lib/resque/worker.rb +487 -163
- data/lib/resque.rb +332 -52
- data/lib/tasks/redis.rake +11 -11
- metadata +169 -149
- data/lib/resque/failure/hoptoad.rb +0 -33
- data/lib/resque/failure/thoughtbot.rb +0 -33
- data/lib/resque/server/public/jquery-1.3.2.min.js +0 -19
- data/lib/resque/server/test_helper.rb +0 -19
- data/lib/resque/vendor/utf8_util/utf8_util_18.rb +0 -91
- data/lib/resque/vendor/utf8_util/utf8_util_19.rb +0 -5
- data/test/airbrake_test.rb +0 -27
- data/test/hoptoad_test.rb +0 -26
- data/test/job_hooks_test.rb +0 -464
- data/test/job_plugins_test.rb +0 -230
- 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_test.rb +0 -278
- data/test/test_helper.rb +0 -178
- data/test/worker_test.rb +0 -657
data/lib/resque.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
+
require 'mono_logger'
|
1
2
|
require 'redis/namespace'
|
3
|
+
require 'forwardable'
|
2
4
|
|
3
5
|
require 'resque/version'
|
4
6
|
|
@@ -9,16 +11,98 @@ require 'resque/failure/base'
|
|
9
11
|
|
10
12
|
require 'resque/helpers'
|
11
13
|
require 'resque/stat'
|
14
|
+
require 'resque/logging'
|
15
|
+
require 'resque/log_formatters/quiet_formatter'
|
16
|
+
require 'resque/log_formatters/verbose_formatter'
|
17
|
+
require 'resque/log_formatters/very_verbose_formatter'
|
12
18
|
require 'resque/job'
|
13
19
|
require 'resque/worker'
|
14
20
|
require 'resque/plugin'
|
21
|
+
require 'resque/data_store'
|
22
|
+
require 'resque/thread_signal'
|
15
23
|
|
16
24
|
require 'resque/vendor/utf8_util'
|
17
25
|
|
26
|
+
require 'resque/railtie' if defined?(Rails::Railtie)
|
27
|
+
|
18
28
|
module Resque
|
19
29
|
include Helpers
|
20
30
|
extend self
|
21
31
|
|
32
|
+
# Given a Ruby object, returns a string suitable for storage in a
|
33
|
+
# queue.
|
34
|
+
def encode(object)
|
35
|
+
if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
|
36
|
+
MultiJson.dump object
|
37
|
+
else
|
38
|
+
MultiJson.encode object
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Given a string, returns a Ruby object.
|
43
|
+
def decode(object)
|
44
|
+
return unless object
|
45
|
+
|
46
|
+
begin
|
47
|
+
if MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
|
48
|
+
MultiJson.load object
|
49
|
+
else
|
50
|
+
MultiJson.decode object
|
51
|
+
end
|
52
|
+
rescue ::MultiJson::DecodeError => e
|
53
|
+
raise Helpers::DecodeException, e.message, e.backtrace
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Given a word with dashes, returns a camel cased version of it.
|
58
|
+
#
|
59
|
+
# classify('job-name') # => 'JobName'
|
60
|
+
def classify(dashed_word)
|
61
|
+
dashed_word.split('-').map(&:capitalize).join
|
62
|
+
end
|
63
|
+
|
64
|
+
# Tries to find a constant with the name specified in the argument string:
|
65
|
+
#
|
66
|
+
# constantize("Module") # => Module
|
67
|
+
# constantize("Test::Unit") # => Test::Unit
|
68
|
+
#
|
69
|
+
# The name is assumed to be the one of a top-level constant, no matter
|
70
|
+
# whether it starts with "::" or not. No lexical context is taken into
|
71
|
+
# account:
|
72
|
+
#
|
73
|
+
# C = 'outside'
|
74
|
+
# module M
|
75
|
+
# C = 'inside'
|
76
|
+
# C # => 'inside'
|
77
|
+
# constantize("C") # => 'outside', same as ::C
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# NameError is raised when the constant is unknown.
|
81
|
+
def constantize(camel_cased_word)
|
82
|
+
camel_cased_word = camel_cased_word.to_s
|
83
|
+
|
84
|
+
if camel_cased_word.include?('-')
|
85
|
+
camel_cased_word = classify(camel_cased_word)
|
86
|
+
end
|
87
|
+
|
88
|
+
names = camel_cased_word.split('::')
|
89
|
+
names.shift if names.empty? || names.first.empty?
|
90
|
+
|
91
|
+
constant = Object
|
92
|
+
names.each do |name|
|
93
|
+
args = Module.method(:const_get).arity != 1 ? [false] : []
|
94
|
+
|
95
|
+
if constant.const_defined?(name, *args)
|
96
|
+
constant = constant.const_get(name)
|
97
|
+
else
|
98
|
+
constant = constant.const_missing(name)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
constant
|
102
|
+
end
|
103
|
+
|
104
|
+
extend ::Forwardable
|
105
|
+
|
22
106
|
# Accepts:
|
23
107
|
# 1. A 'hostname:port' String
|
24
108
|
# 2. A 'hostname:port:db' String (to select the Redis db)
|
@@ -26,43 +110,113 @@ module Resque
|
|
26
110
|
# 4. A Redis URL String 'redis://host:port'
|
27
111
|
# 5. An instance of `Redis`, `Redis::Client`, `Redis::DistRedis`,
|
28
112
|
# or `Redis::Namespace`.
|
113
|
+
# 6. An Hash of a redis connection {:host => 'localhost', :port => 6379, :db => 0}
|
29
114
|
def redis=(server)
|
30
115
|
case server
|
31
116
|
when String
|
32
|
-
if server =~ /
|
33
|
-
redis = Redis.
|
117
|
+
if server =~ /rediss?\:\/\//
|
118
|
+
redis = Redis.new(:url => server)
|
34
119
|
else
|
35
120
|
server, namespace = server.split('/', 2)
|
36
121
|
host, port, db = server.split(':')
|
37
|
-
redis = Redis.new(:host => host, :port => port,
|
38
|
-
:thread_safe => true, :db => db)
|
122
|
+
redis = Redis.new(:host => host, :port => port, :db => db)
|
39
123
|
end
|
40
124
|
namespace ||= :resque
|
41
125
|
|
42
|
-
@
|
126
|
+
@data_store = Resque::DataStore.new(Redis::Namespace.new(namespace, :redis => redis))
|
43
127
|
when Redis::Namespace
|
44
|
-
@
|
128
|
+
@data_store = Resque::DataStore.new(server)
|
129
|
+
when Resque::DataStore
|
130
|
+
@data_store = server
|
131
|
+
when Hash
|
132
|
+
@data_store = Resque::DataStore.new(Redis::Namespace.new(:resque, :redis => Redis.new(server)))
|
45
133
|
else
|
46
|
-
@
|
134
|
+
@data_store = Resque::DataStore.new(Redis::Namespace.new(:resque, :redis => server))
|
47
135
|
end
|
48
136
|
end
|
49
137
|
|
50
138
|
# Returns the current Redis connection. If none has been created, will
|
51
139
|
# create a new one.
|
52
140
|
def redis
|
53
|
-
return @
|
141
|
+
return @data_store if @data_store
|
54
142
|
self.redis = Redis.respond_to?(:connect) ? Redis.connect : "localhost:6379"
|
55
143
|
self.redis
|
56
144
|
end
|
145
|
+
alias :data_store :redis
|
57
146
|
|
58
147
|
def redis_id
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
148
|
+
data_store.identifier
|
149
|
+
end
|
150
|
+
|
151
|
+
# Set the data store for the processed and failed statistics.
|
152
|
+
#
|
153
|
+
# By default it uses the same as `Resque.redis`, but different stores can be used.
|
154
|
+
#
|
155
|
+
# A custom store needs to obey the following API to work correctly
|
156
|
+
#
|
157
|
+
# class NullDataStore
|
158
|
+
# # Returns the current value for the given stat.
|
159
|
+
# def stat(stat)
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# # Increments the stat by the given value.
|
163
|
+
# def increment_stat(stat, by)
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# # Decrements the stat by the given value.
|
167
|
+
# def decrement_stat(stat, by)
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# # Clear the values for the given stat.
|
171
|
+
# def clear_stat(stat)
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
def stat_data_store=(stat_data_store)
|
175
|
+
Resque::Stat.data_store = stat_data_store
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns the data store for the statistics module.
|
179
|
+
def stat_data_store
|
180
|
+
Resque::Stat.data_store
|
181
|
+
end
|
182
|
+
|
183
|
+
# Set or retrieve the current logger object
|
184
|
+
attr_accessor :logger
|
185
|
+
|
186
|
+
DEFAULT_HEARTBEAT_INTERVAL = 60
|
187
|
+
DEFAULT_PRUNE_INTERVAL = DEFAULT_HEARTBEAT_INTERVAL * 5
|
188
|
+
|
189
|
+
# Defines how often a Resque worker updates the heartbeat key. Must be less
|
190
|
+
# than the prune interval.
|
191
|
+
attr_writer :heartbeat_interval
|
192
|
+
def heartbeat_interval
|
193
|
+
if defined? @heartbeat_interval
|
194
|
+
@heartbeat_interval
|
64
195
|
else
|
65
|
-
|
196
|
+
DEFAULT_HEARTBEAT_INTERVAL
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Defines how often Resque checks for dead workers.
|
201
|
+
attr_writer :prune_interval
|
202
|
+
def prune_interval
|
203
|
+
if defined? @prune_interval
|
204
|
+
@prune_interval
|
205
|
+
else
|
206
|
+
DEFAULT_PRUNE_INTERVAL
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# By default, jobs are pushed to the back of the queue and popped from
|
211
|
+
# the front, resulting in "first in, first out" (FIFO) execution order.
|
212
|
+
# Set to true to push jobs to the front of the queue instead, resulting
|
213
|
+
# in "last in, first out" (LIFO) execution order.
|
214
|
+
attr_writer :enqueue_front
|
215
|
+
def enqueue_front
|
216
|
+
if defined? @enqueue_front
|
217
|
+
@enqueue_front
|
218
|
+
else
|
219
|
+
@enqueue_front = false
|
66
220
|
end
|
67
221
|
end
|
68
222
|
|
@@ -71,41 +225,96 @@ module Resque
|
|
71
225
|
# changes you make will be permanent for the lifespan of the
|
72
226
|
# worker.
|
73
227
|
#
|
74
|
-
# Call with a block to
|
75
|
-
# Call with no arguments to return
|
228
|
+
# Call with a block to register a hook.
|
229
|
+
# Call with no arguments to return all registered hooks.
|
76
230
|
def before_first_fork(&block)
|
77
|
-
block ? (
|
231
|
+
block ? register_hook(:before_first_fork, block) : hooks(:before_first_fork)
|
78
232
|
end
|
79
233
|
|
80
|
-
#
|
81
|
-
|
82
|
-
|
234
|
+
# Register a before_first_fork proc.
|
235
|
+
def before_first_fork=(block)
|
236
|
+
register_hook(:before_first_fork, block)
|
237
|
+
end
|
83
238
|
|
84
239
|
# The `before_fork` hook will be run in the **parent** process
|
85
240
|
# before every job, so be careful- any changes you make will be
|
86
241
|
# permanent for the lifespan of the worker.
|
87
242
|
#
|
88
|
-
# Call with a block to
|
89
|
-
# Call with no arguments to return
|
243
|
+
# Call with a block to register a hook.
|
244
|
+
# Call with no arguments to return all registered hooks.
|
90
245
|
def before_fork(&block)
|
91
|
-
block ? (
|
246
|
+
block ? register_hook(:before_fork, block) : hooks(:before_fork)
|
92
247
|
end
|
93
248
|
|
94
|
-
#
|
95
|
-
|
249
|
+
# Register a before_fork proc.
|
250
|
+
def before_fork=(block)
|
251
|
+
register_hook(:before_fork, block)
|
252
|
+
end
|
96
253
|
|
97
254
|
# The `after_fork` hook will be run in the child process and is passed
|
98
255
|
# the current job. Any changes you make, therefore, will only live as
|
99
256
|
# long as the job currently being processed.
|
100
257
|
#
|
101
|
-
# Call with a block to
|
102
|
-
# Call with no arguments to return
|
258
|
+
# Call with a block to register a hook.
|
259
|
+
# Call with no arguments to return all registered hooks.
|
103
260
|
def after_fork(&block)
|
104
|
-
block ? (
|
261
|
+
block ? register_hook(:after_fork, block) : hooks(:after_fork)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Register an after_fork proc.
|
265
|
+
def after_fork=(block)
|
266
|
+
register_hook(:after_fork, block)
|
267
|
+
end
|
268
|
+
|
269
|
+
# The `before_pause` hook will be run in the parent process before the
|
270
|
+
# worker has paused processing (via #pause_processing or SIGUSR2).
|
271
|
+
def before_pause(&block)
|
272
|
+
block ? register_hook(:before_pause, block) : hooks(:before_pause)
|
273
|
+
end
|
274
|
+
|
275
|
+
# Register a before_pause proc.
|
276
|
+
def before_pause=(block)
|
277
|
+
register_hook(:before_pause, block)
|
278
|
+
end
|
279
|
+
|
280
|
+
# The `after_pause` hook will be run in the parent process after the
|
281
|
+
# worker has paused (via SIGCONT).
|
282
|
+
def after_pause(&block)
|
283
|
+
block ? register_hook(:after_pause, block) : hooks(:after_pause)
|
284
|
+
end
|
285
|
+
|
286
|
+
# Register an after_pause proc.
|
287
|
+
def after_pause=(block)
|
288
|
+
register_hook(:after_pause, block)
|
289
|
+
end
|
290
|
+
|
291
|
+
# The `queue_empty` hook will be run in the **parent** process when
|
292
|
+
# the worker finds no more jobs in the queue and becomes idle.
|
293
|
+
#
|
294
|
+
# Call with a block to register a hook.
|
295
|
+
# Call with no arguments to return all registered hooks.
|
296
|
+
def queue_empty(&block)
|
297
|
+
block ? register_hook(:queue_empty, block) : hooks(:queue_empty)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Register a queue_empty proc.
|
301
|
+
def queue_empty=(block)
|
302
|
+
register_hook(:queue_empty, block)
|
105
303
|
end
|
106
304
|
|
107
|
-
#
|
108
|
-
|
305
|
+
# The `worker_exit` hook will be run in the **parent** process
|
306
|
+
# after the worker has existed (via SIGQUIT, SIGTERM, SIGINT, etc.).
|
307
|
+
#
|
308
|
+
# Call with a block to register a hook.
|
309
|
+
# Call with no arguments to return all registered hooks.
|
310
|
+
def worker_exit(&block)
|
311
|
+
block ? register_hook(:worker_exit, block) : hooks(:worker_exit)
|
312
|
+
end
|
313
|
+
|
314
|
+
# Register a worker_exit proc.
|
315
|
+
def worker_exit=(block)
|
316
|
+
register_hook(:worker_exit, block)
|
317
|
+
end
|
109
318
|
|
110
319
|
def to_s
|
111
320
|
"Resque Client connected to #{redis_id}"
|
@@ -138,25 +347,24 @@ module Resque
|
|
138
347
|
#
|
139
348
|
# Returns nothing
|
140
349
|
def push(queue, item)
|
141
|
-
|
142
|
-
redis.rpush "queue:#{queue}", encode(item)
|
350
|
+
data_store.push_to_queue(queue,encode(item))
|
143
351
|
end
|
144
352
|
|
145
353
|
# Pops a job off a queue. Queue name should be a string.
|
146
354
|
#
|
147
355
|
# Returns a Ruby object.
|
148
356
|
def pop(queue)
|
149
|
-
decode
|
357
|
+
decode(data_store.pop_from_queue(queue))
|
150
358
|
end
|
151
359
|
|
152
360
|
# Returns an integer representing the size of a queue.
|
153
361
|
# Queue name should be a string.
|
154
362
|
def size(queue)
|
155
|
-
|
363
|
+
data_store.queue_size(queue)
|
156
364
|
end
|
157
365
|
|
158
|
-
# Returns an array of items currently queued
|
159
|
-
# a string.
|
366
|
+
# Returns an array of items currently queued, or the item itself
|
367
|
+
# if count = 1. Queue name should be a string.
|
160
368
|
#
|
161
369
|
# start and count should be integer and can be used for pagination.
|
162
370
|
# start is the item to begin, count is how many items to return.
|
@@ -164,36 +372,39 @@ module Resque
|
|
164
372
|
# To get the 3rd page of a 30 item, paginatied list one would use:
|
165
373
|
# Resque.peek('my_list', 59, 30)
|
166
374
|
def peek(queue, start = 0, count = 1)
|
167
|
-
|
375
|
+
results = data_store.peek_in_queue(queue,start,count)
|
376
|
+
if count == 1
|
377
|
+
decode(results)
|
378
|
+
else
|
379
|
+
results.map { |result| decode(result) }
|
380
|
+
end
|
168
381
|
end
|
169
382
|
|
170
383
|
# Does the dirty work of fetching a range of items from a Redis list
|
171
384
|
# and converting them into Ruby objects.
|
172
385
|
def list_range(key, start = 0, count = 1)
|
386
|
+
results = data_store.list_range(key, start, count)
|
173
387
|
if count == 1
|
174
|
-
decode
|
388
|
+
decode(results)
|
175
389
|
else
|
176
|
-
|
177
|
-
decode item
|
178
|
-
end
|
390
|
+
results.map { |result| decode(result) }
|
179
391
|
end
|
180
392
|
end
|
181
393
|
|
182
394
|
# Returns an array of all known Resque queues as strings.
|
183
395
|
def queues
|
184
|
-
|
396
|
+
data_store.queue_names
|
185
397
|
end
|
186
398
|
|
187
399
|
# Given a queue name, completely deletes the queue.
|
188
400
|
def remove_queue(queue)
|
189
|
-
|
190
|
-
redis.del("queue:#{queue}")
|
401
|
+
data_store.remove_queue(queue)
|
191
402
|
end
|
192
403
|
|
193
404
|
# Used internally to keep track of which queues we've created.
|
194
405
|
# Don't call this directly.
|
195
406
|
def watch_queue(queue)
|
196
|
-
|
407
|
+
data_store.watch_queue(queue)
|
197
408
|
end
|
198
409
|
|
199
410
|
|
@@ -280,17 +491,19 @@ module Resque
|
|
280
491
|
end
|
281
492
|
return if before_hooks.any? { |result| result == false }
|
282
493
|
|
283
|
-
Job.destroy(queue_from_class(klass), klass, *args)
|
494
|
+
destroyed = Job.destroy(queue_from_class(klass), klass, *args)
|
284
495
|
|
285
496
|
Plugin.after_dequeue_hooks(klass).each do |hook|
|
286
497
|
klass.send(hook, *args)
|
287
498
|
end
|
499
|
+
|
500
|
+
destroyed
|
288
501
|
end
|
289
502
|
|
290
503
|
# Given a class, try to extrapolate an appropriate queue based on a
|
291
504
|
# class instance variable or `queue` method.
|
292
505
|
def queue_from_class(klass)
|
293
|
-
klass.instance_variable_get(:@queue) ||
|
506
|
+
(klass.instance_variable_defined?(:@queue) && klass.instance_variable_get(:@queue)) ||
|
294
507
|
(klass.respond_to?(:queue) and klass.queue)
|
295
508
|
end
|
296
509
|
|
@@ -312,7 +525,7 @@ module Resque
|
|
312
525
|
queue ||= queue_from_class(klass)
|
313
526
|
|
314
527
|
if !queue
|
315
|
-
raise NoQueueError.new("Jobs must be placed onto a queue.")
|
528
|
+
raise NoQueueError.new("Jobs must be placed onto a queue. No queue could be inferred for class #{klass}")
|
316
529
|
end
|
317
530
|
|
318
531
|
if klass.to_s.empty?
|
@@ -349,12 +562,12 @@ module Resque
|
|
349
562
|
# Returns a hash, similar to redis-rb's #info, of interesting stats.
|
350
563
|
def info
|
351
564
|
return {
|
352
|
-
:pending =>
|
565
|
+
:pending => queue_sizes.inject(0) { |sum, (_queue_name, queue_size)| sum + queue_size },
|
353
566
|
:processed => Stat[:processed],
|
354
567
|
:queues => queues.size,
|
355
568
|
:workers => workers.size.to_i,
|
356
569
|
:working => working.size,
|
357
|
-
:failed =>
|
570
|
+
:failed => data_store.num_failed,
|
358
571
|
:servers => [redis_id],
|
359
572
|
:environment => ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
360
573
|
}
|
@@ -363,9 +576,76 @@ module Resque
|
|
363
576
|
# Returns an array of all known Resque keys in Redis. Redis' KEYS operation
|
364
577
|
# is O(N) for the keyspace, so be careful - this can be slow for big databases.
|
365
578
|
def keys
|
366
|
-
|
367
|
-
|
579
|
+
data_store.all_resque_keys
|
580
|
+
end
|
581
|
+
|
582
|
+
# Returns a hash, mapping queue names to queue sizes
|
583
|
+
def queue_sizes
|
584
|
+
queue_names = queues
|
585
|
+
|
586
|
+
sizes = redis.pipelined do |piped|
|
587
|
+
queue_names.each do |name|
|
588
|
+
piped.llen("queue:#{name}")
|
589
|
+
end
|
368
590
|
end
|
591
|
+
|
592
|
+
Hash[queue_names.zip(sizes)]
|
593
|
+
end
|
594
|
+
|
595
|
+
# Returns a hash, mapping queue names to (up to `sample_size`) samples of jobs in that queue
|
596
|
+
def sample_queues(sample_size = 1000)
|
597
|
+
queue_names = queues
|
598
|
+
|
599
|
+
samples = redis.pipelined do |piped|
|
600
|
+
queue_names.each do |name|
|
601
|
+
key = "queue:#{name}"
|
602
|
+
piped.llen(key)
|
603
|
+
piped.lrange(key, 0, sample_size - 1)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
hash = {}
|
608
|
+
|
609
|
+
queue_names.zip(samples.each_slice(2).to_a) do |queue_name, (queue_size, serialized_samples)|
|
610
|
+
samples = serialized_samples.map do |serialized_sample|
|
611
|
+
Job.decode(serialized_sample)
|
612
|
+
end
|
613
|
+
|
614
|
+
hash[queue_name] = {
|
615
|
+
:size => queue_size,
|
616
|
+
:samples => samples
|
617
|
+
}
|
618
|
+
end
|
619
|
+
|
620
|
+
hash
|
621
|
+
end
|
622
|
+
|
623
|
+
private
|
624
|
+
|
625
|
+
@hooks = Hash.new { |h, k| h[k] = [] }
|
626
|
+
|
627
|
+
# Register a new proc as a hook. If the block is nil this is the
|
628
|
+
# equivalent of removing all hooks of the given name.
|
629
|
+
#
|
630
|
+
# `name` is the hook that the block should be registered with.
|
631
|
+
def register_hook(name, block)
|
632
|
+
return clear_hooks(name) if block.nil?
|
633
|
+
|
634
|
+
block = Array(block)
|
635
|
+
@hooks[name].concat(block)
|
636
|
+
end
|
637
|
+
|
638
|
+
# Clear all hooks given a hook name.
|
639
|
+
def clear_hooks(name)
|
640
|
+
@hooks[name] = []
|
641
|
+
end
|
642
|
+
|
643
|
+
# Retrieve all hooks of a given name.
|
644
|
+
def hooks(name)
|
645
|
+
@hooks[name]
|
369
646
|
end
|
370
647
|
end
|
371
648
|
|
649
|
+
# Log to STDOUT by default
|
650
|
+
Resque.logger = MonoLogger.new(STDOUT)
|
651
|
+
Resque.logger.formatter = Resque::QuietFormatter.new
|
data/lib/tasks/redis.rake
CHANGED
@@ -17,7 +17,7 @@ class RedisRunner
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.config
|
20
|
-
@config ||= if File.
|
20
|
+
@config ||= if File.exist?(redis_dir + 'etc/redis.conf')
|
21
21
|
redis_dir + 'etc/redis.conf'
|
22
22
|
else
|
23
23
|
redis_dir + '../etc/redis.conf'
|
@@ -30,7 +30,7 @@ class RedisRunner
|
|
30
30
|
|
31
31
|
# Just check for existance of dtach socket
|
32
32
|
def self.running?
|
33
|
-
File.
|
33
|
+
File.exist? dtach_socket
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.start
|
@@ -79,7 +79,7 @@ namespace :redis do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
desc <<-DOC
|
82
|
-
Install the latest
|
82
|
+
Install the latest version of Redis from Github (requires git, duh).
|
83
83
|
Use INSTALL_DIR env var like "rake redis:install INSTALL_DIR=~/tmp"
|
84
84
|
in order to get an alternate location for your install files.
|
85
85
|
DOC
|
@@ -90,10 +90,10 @@ namespace :redis do
|
|
90
90
|
|
91
91
|
if ENV['PREFIX']
|
92
92
|
bin_dir = "#{ENV['PREFIX']}/bin"
|
93
|
-
sh "mkdir -p #{bin_dir}" unless File.
|
93
|
+
sh "mkdir -p #{bin_dir}" unless File.exist?("#{bin_dir}")
|
94
94
|
|
95
95
|
conf_dir = "#{ENV['PREFIX']}/etc"
|
96
|
-
sh "mkdir -p #{conf_dir}" unless File.
|
96
|
+
sh "mkdir -p #{conf_dir}" unless File.exist?("#{conf_dir}")
|
97
97
|
end
|
98
98
|
|
99
99
|
%w(redis-benchmark redis-cli redis-server).each do |bin|
|
@@ -102,7 +102,7 @@ namespace :redis do
|
|
102
102
|
|
103
103
|
puts "Installed redis-benchmark, redis-cli and redis-server to #{bin_dir}"
|
104
104
|
|
105
|
-
unless File.
|
105
|
+
unless File.exist?("#{conf_dir}/redis.conf")
|
106
106
|
sh "cp #{INSTALL_DIR}/redis.conf #{conf_dir}/redis.conf"
|
107
107
|
puts "Installed redis.conf to #{conf_dir} \n You should look at this file!"
|
108
108
|
end
|
@@ -115,9 +115,9 @@ namespace :redis do
|
|
115
115
|
|
116
116
|
desc "Download package"
|
117
117
|
task :download do
|
118
|
-
sh "rm -rf #{INSTALL_DIR}/" if File.
|
119
|
-
sh "git clone git://github.com/antirez/redis.git #{INSTALL_DIR}" unless File.
|
120
|
-
sh "cd #{INSTALL_DIR} && git pull" if File.
|
118
|
+
sh "rm -rf #{INSTALL_DIR}/" if File.exist?("#{INSTALL_DIR}/.svn")
|
119
|
+
sh "git clone git://github.com/antirez/redis.git #{INSTALL_DIR}" unless File.exist?(INSTALL_DIR)
|
120
|
+
sh "cd #{INSTALL_DIR} && git pull" if File.exist?("#{INSTALL_DIR}/.git")
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
@@ -135,7 +135,7 @@ namespace :dtach do
|
|
135
135
|
|
136
136
|
if ENV['PREFIX']
|
137
137
|
bin_dir = "#{ENV['PREFIX']}/bin"
|
138
|
-
sh "mkdir -p #{bin_dir}" unless File.
|
138
|
+
sh "mkdir -p #{bin_dir}" unless File.exist?("#{bin_dir}")
|
139
139
|
end
|
140
140
|
|
141
141
|
sh "cp #{INSTALL_DIR}/dtach-0.8/dtach #{bin_dir}"
|
@@ -147,7 +147,7 @@ namespace :dtach do
|
|
147
147
|
|
148
148
|
desc "Download package"
|
149
149
|
task :download do
|
150
|
-
unless File.
|
150
|
+
unless File.exist?("#{INSTALL_DIR}/dtach-0.8.tar.gz")
|
151
151
|
require 'net/http'
|
152
152
|
|
153
153
|
url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
|