resque_sqs 1.25.2

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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.md +467 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +866 -0
  5. data/Rakefile +70 -0
  6. data/bin/resque-sqs +81 -0
  7. data/bin/resque-sqs-web +27 -0
  8. data/lib/resque_sqs/errors.rb +13 -0
  9. data/lib/resque_sqs/failure/airbrake.rb +33 -0
  10. data/lib/resque_sqs/failure/base.rb +73 -0
  11. data/lib/resque_sqs/failure/multiple.rb +59 -0
  12. data/lib/resque_sqs/failure/redis.rb +108 -0
  13. data/lib/resque_sqs/failure/redis_multi_queue.rb +89 -0
  14. data/lib/resque_sqs/failure.rb +113 -0
  15. data/lib/resque_sqs/helpers.rb +107 -0
  16. data/lib/resque_sqs/job.rb +346 -0
  17. data/lib/resque_sqs/log_formatters/quiet_formatter.rb +7 -0
  18. data/lib/resque_sqs/log_formatters/verbose_formatter.rb +7 -0
  19. data/lib/resque_sqs/log_formatters/very_verbose_formatter.rb +8 -0
  20. data/lib/resque_sqs/logging.rb +18 -0
  21. data/lib/resque_sqs/plugin.rb +66 -0
  22. data/lib/resque_sqs/server/helpers.rb +52 -0
  23. data/lib/resque_sqs/server/public/favicon.ico +0 -0
  24. data/lib/resque_sqs/server/public/idle.png +0 -0
  25. data/lib/resque_sqs/server/public/jquery-1.3.2.min.js +19 -0
  26. data/lib/resque_sqs/server/public/jquery.relatize_date.js +95 -0
  27. data/lib/resque_sqs/server/public/poll.png +0 -0
  28. data/lib/resque_sqs/server/public/ranger.js +78 -0
  29. data/lib/resque_sqs/server/public/reset.css +44 -0
  30. data/lib/resque_sqs/server/public/style.css +91 -0
  31. data/lib/resque_sqs/server/public/working.png +0 -0
  32. data/lib/resque_sqs/server/test_helper.rb +19 -0
  33. data/lib/resque_sqs/server/views/error.erb +1 -0
  34. data/lib/resque_sqs/server/views/failed.erb +29 -0
  35. data/lib/resque_sqs/server/views/failed_job.erb +50 -0
  36. data/lib/resque_sqs/server/views/failed_queues_overview.erb +24 -0
  37. data/lib/resque_sqs/server/views/key_sets.erb +19 -0
  38. data/lib/resque_sqs/server/views/key_string.erb +11 -0
  39. data/lib/resque_sqs/server/views/layout.erb +44 -0
  40. data/lib/resque_sqs/server/views/next_more.erb +22 -0
  41. data/lib/resque_sqs/server/views/overview.erb +4 -0
  42. data/lib/resque_sqs/server/views/queues.erb +58 -0
  43. data/lib/resque_sqs/server/views/stats.erb +62 -0
  44. data/lib/resque_sqs/server/views/workers.erb +109 -0
  45. data/lib/resque_sqs/server/views/working.erb +72 -0
  46. data/lib/resque_sqs/server.rb +271 -0
  47. data/lib/resque_sqs/stat.rb +57 -0
  48. data/lib/resque_sqs/tasks.rb +83 -0
  49. data/lib/resque_sqs/vendor/utf8_util/utf8_util_18.rb +91 -0
  50. data/lib/resque_sqs/vendor/utf8_util/utf8_util_19.rb +5 -0
  51. data/lib/resque_sqs/vendor/utf8_util.rb +20 -0
  52. data/lib/resque_sqs/version.rb +3 -0
  53. data/lib/resque_sqs/worker.rb +779 -0
  54. data/lib/resque_sqs.rb +479 -0
  55. data/lib/tasks/redis_sqs.rake +161 -0
  56. data/lib/tasks/resque_sqs.rake +2 -0
  57. data/test/airbrake_test.rb +27 -0
  58. data/test/failure_base_test.rb +15 -0
  59. data/test/job_hooks_test.rb +465 -0
  60. data/test/job_plugins_test.rb +230 -0
  61. data/test/logging_test.rb +24 -0
  62. data/test/plugin_test.rb +116 -0
  63. data/test/redis-test-cluster.conf +115 -0
  64. data/test/redis-test.conf +115 -0
  65. data/test/resque-web_test.rb +59 -0
  66. data/test/resque_failure_redis_test.rb +19 -0
  67. data/test/resque_hook_test.rb +165 -0
  68. data/test/resque_test.rb +278 -0
  69. data/test/stdout +42 -0
  70. data/test/test_helper.rb +228 -0
  71. data/test/worker_test.rb +1080 -0
  72. metadata +202 -0
data/Rakefile ADDED
@@ -0,0 +1,70 @@
1
+ #
2
+ # Setup
3
+ #
4
+
5
+ load 'lib/tasks/redis_sqs.rake'
6
+
7
+ $LOAD_PATH.unshift 'lib'
8
+ require 'resque_sqs/tasks'
9
+
10
+ def command?(command)
11
+ system("type #{command} > /dev/null 2>&1")
12
+ end
13
+
14
+
15
+ #
16
+ # Tests
17
+ #
18
+
19
+ require 'rake/testtask'
20
+
21
+ task :default => :test
22
+
23
+ Rake::TestTask.new do |test|
24
+ test.verbose = true
25
+ test.libs << "test"
26
+ test.libs << "lib"
27
+ test.test_files = FileList['test/**/*_test.rb']
28
+ end
29
+
30
+ if command? :kicker
31
+ desc "Launch Kicker (like autotest)"
32
+ task :kicker do
33
+ puts "Kicking... (ctrl+c to cancel)"
34
+ exec "kicker -e rake test lib examples"
35
+ end
36
+ end
37
+
38
+
39
+ #
40
+ # Install
41
+ #
42
+
43
+ task :install => [ 'redis_sqs:install', 'dtach_sqs:install' ]
44
+
45
+
46
+ #
47
+ # Documentation
48
+ #
49
+
50
+ begin
51
+ require 'sdoc_helpers'
52
+ rescue LoadError
53
+ end
54
+
55
+
56
+ #
57
+ # Publishing
58
+ #
59
+
60
+ desc "Push a new version to Gemcutter"
61
+ task :sqs_publish do
62
+ require 'resque_sqs/version'
63
+
64
+ sh "gem build resque_sqs.gemspec"
65
+ sh "gem push resque_sqs-#{ResqueSqs::Version}.gem"
66
+ sh "git tag v#{ResqueSqs::Version}"
67
+ sh "git push origin v#{ResqueSqs::Version}"
68
+ sh "git push origin master"
69
+ sh "git clean -fd"
70
+ end
data/bin/resque-sqs ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ begin
5
+ require 'redis-namespace'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'redis-namespace'
9
+ end
10
+ require 'resque_sqs'
11
+ require 'optparse'
12
+
13
+ parser = OptionParser.new do |opts|
14
+ opts.banner = "Usage: resque [options] COMMAND"
15
+
16
+ opts.separator ""
17
+ opts.separator "Options:"
18
+
19
+ opts.on("-r", "--redis [HOST:PORT]", "Redis connection string") do |host|
20
+ ResqueSqs.redis = host
21
+ end
22
+
23
+ opts.on("-N", "--namespace [NAMESPACE]", "Redis namespace") do |namespace|
24
+ ResqueSqs.redis.namespace = namespace
25
+ end
26
+
27
+ opts.on("-h", "--help", "Show this message") do
28
+ puts opts
29
+ exit
30
+ end
31
+
32
+ opts.separator ""
33
+ opts.separator "Commands:"
34
+ opts.separator " remove WORKER Removes a worker"
35
+ opts.separator " kill WORKER Kills a worker"
36
+ opts.separator " list Lists known workers"
37
+ end
38
+
39
+ def kill(worker)
40
+ abort "** resque kill WORKER_ID" if worker.nil?
41
+ pid = worker.split(':')[1].to_i
42
+
43
+ begin
44
+ Process.kill("KILL", pid)
45
+ puts "** killed #{worker}"
46
+ rescue Errno::ESRCH
47
+ puts "** worker #{worker} not running"
48
+ end
49
+
50
+ remove worker
51
+ end
52
+
53
+ def remove(worker)
54
+ abort "** resque remove WORKER_ID" if worker.nil?
55
+
56
+ ResqueSqs.remove_worker(worker)
57
+ puts "** removed #{worker}"
58
+ end
59
+
60
+ def list
61
+ if ResqueSqs.workers.any?
62
+ ResqueSqs.workers.each do |worker|
63
+ puts "#{worker} (#{worker.state})"
64
+ end
65
+ else
66
+ puts "None"
67
+ end
68
+ end
69
+
70
+ parser.parse!
71
+
72
+ case ARGV[0]
73
+ when 'kill'
74
+ kill ARGV[1]
75
+ when 'remove'
76
+ remove ARGV[1]
77
+ when 'list'
78
+ list
79
+ else
80
+ puts parser.help
81
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ begin
5
+ require 'vegas'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'vegas'
9
+ end
10
+ require 'resque_sqs/server'
11
+
12
+
13
+ Vegas::Runner.new(ResqueSqs::Server, 'resque-web', {
14
+ :before_run => lambda {|v|
15
+ path = (ENV['RESQUECONFIG'] || v.args.first)
16
+ load path.to_s.strip if path
17
+ }
18
+ }) do |runner, opts, app|
19
+ opts.on('-N NAMESPACE', "--namespace NAMESPACE", "set the Redis namespace") {|namespace|
20
+ runner.logger.info "Using Redis namespace '#{namespace}'"
21
+ ResqueSqs.redis.namespace = namespace
22
+ }
23
+ opts.on('-r redis-connection', "--redis redis-connection", "set the Redis connection string") {|redis_conf|
24
+ runner.logger.info "Using Redis connection '#{redis_conf}'"
25
+ ResqueSqs.redis = redis_conf
26
+ }
27
+ end
@@ -0,0 +1,13 @@
1
+ module ResqueSqs
2
+ # Raised whenever we need a queue but none is provided.
3
+ class NoQueueError < RuntimeError; end
4
+
5
+ # Raised when trying to create a job without a class
6
+ class NoClassError < RuntimeError; end
7
+
8
+ # Raised when a worker was killed while processing a job.
9
+ class DirtyExit < RuntimeError; end
10
+
11
+ # Raised when child process is TERM'd so job can rescue this to do shutdown work.
12
+ class TermException < SignalException; end
13
+ end
@@ -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 ResqueSqs
8
+ module Failure
9
+ class Airbrake < Base
10
+ def self.configure(&block)
11
+ ResqueSqs.logger.warn "This actually sets global Airbrake configuration, " \
12
+ "which is probably not what you want. This will be gone in 2.0."
13
+ ResqueSqs::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_or_ignore(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 ResqueSqs
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(index)
62
+ end
63
+
64
+ def self.remove(index)
65
+ end
66
+
67
+ # Logging!
68
+ def log(message)
69
+ @worker.log(message)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,59 @@
1
+ module ResqueSqs
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
+ ResqueSqs::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 a paginated array of failure objects.
31
+ def self.all(*args)
32
+ classes.first.all(*args)
33
+ end
34
+
35
+ # Iterate across failed objects
36
+ def self.each(*args, &block)
37
+ classes.first.each(*args, &block)
38
+ end
39
+
40
+ # A URL where someone can go to view failures.
41
+ def self.url
42
+ classes.first.url
43
+ end
44
+
45
+ # Clear all failure objects
46
+ def self.clear(*args)
47
+ classes.first.clear(*args)
48
+ end
49
+
50
+ def self.requeue(*args)
51
+ classes.first.requeue(*args)
52
+ end
53
+
54
+ def self.remove(index)
55
+ classes.each { |klass| klass.remove(index) }
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,108 @@
1
+ module ResqueSqs
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
+ def save
7
+ data = {
8
+ :failed_at => UTF8Util.clean(Time.now.strftime("%Y/%m/%d %H:%M:%S %Z")),
9
+ :payload => payload,
10
+ :exception => exception.class.to_s,
11
+ :error => UTF8Util.clean(exception.to_s),
12
+ :backtrace => filter_backtrace(Array(exception.backtrace)),
13
+ :worker => worker.to_s,
14
+ :queue => queue
15
+ }
16
+ data = ResqueSqs.encode(data)
17
+ ResqueSqs.redis.rpush(:failed, data)
18
+ end
19
+
20
+ def self.count(queue = nil, class_name = nil)
21
+ check_queue(queue)
22
+
23
+ if class_name
24
+ n = 0
25
+ each(0, count(queue), queue, class_name) { n += 1 }
26
+ n
27
+ else
28
+ ResqueSqs.redis.llen(:failed).to_i
29
+ end
30
+ end
31
+
32
+ def self.queues
33
+ [:failed]
34
+ end
35
+
36
+ def self.all(offset = 0, limit = 1, queue = nil)
37
+ check_queue(queue)
38
+ ResqueSqs.list_range(:failed, offset, limit)
39
+ end
40
+
41
+ def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
42
+ all_items = Array(all(offset, limit, queue))
43
+ reversed = false
44
+ if order.eql? 'desc'
45
+ all_items.reverse!
46
+ reversed = true
47
+ end
48
+ all_items.each_with_index do |item, i|
49
+ if !class_name || (item['payload'] && item['payload']['class'] == class_name)
50
+ if reversed
51
+ id = (all_items.length - 1) - (offset + i)
52
+ else
53
+ id = offset + i
54
+ end
55
+ yield id, item
56
+ end
57
+ end
58
+ end
59
+
60
+ def self.clear(queue = nil)
61
+ check_queue(queue)
62
+ ResqueSqs.redis.del(:failed)
63
+ end
64
+
65
+ def self.requeue(id)
66
+ item = all(id)
67
+ item['retried_at'] = Time.now.strftime("%Y/%m/%d %H:%M:%S")
68
+ ResqueSqs.redis.lset(:failed, id, ResqueSqs.encode(item))
69
+ Job.create(item['queue'], item['payload']['class'], *item['payload']['args'])
70
+ end
71
+
72
+ def self.remove(id)
73
+ sentinel = ""
74
+ ResqueSqs.redis.lset(:failed, id, sentinel)
75
+ ResqueSqs.redis.lrem(:failed, 1, sentinel)
76
+ end
77
+
78
+ def self.requeue_queue(queue)
79
+ i = 0
80
+ while job = all(i)
81
+ requeue(i) if job['queue'] == queue
82
+ i += 1
83
+ end
84
+ end
85
+
86
+ def self.remove_queue(queue)
87
+ i = 0
88
+ while job = all(i)
89
+ if job['queue'] == queue
90
+ # This will remove the failure from the array so do not increment the index.
91
+ remove(i)
92
+ else
93
+ i += 1
94
+ end
95
+ end
96
+ end
97
+
98
+ def self.check_queue(queue)
99
+ raise ArgumentError, "invalid queue: #{queue}" if queue && queue.to_s != "failed"
100
+ end
101
+
102
+ def filter_backtrace(backtrace)
103
+ index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
104
+ backtrace.first(index.to_i)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,89 @@
1
+ module ResqueSqs
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
+ def save
7
+ data = {
8
+ :failed_at => Time.now.strftime("%Y/%m/%d %H:%M:%S %Z"),
9
+ :payload => payload,
10
+ :exception => exception.class.to_s,
11
+ :error => UTF8Util.clean(exception.to_s),
12
+ :backtrace => filter_backtrace(Array(exception.backtrace)),
13
+ :worker => worker.to_s,
14
+ :queue => queue
15
+ }
16
+ data = ResqueSqs.encode(data)
17
+ ResqueSqs.redis.rpush(ResqueSqs::Failure.failure_queue_name(queue), data)
18
+ end
19
+
20
+ def self.count(queue = nil, class_name = nil)
21
+ if queue
22
+ if class_name
23
+ n = 0
24
+ each(0, count(queue), queue, class_name) { n += 1 }
25
+ n
26
+ else
27
+ ResqueSqs.redis.llen(queue).to_i
28
+ end
29
+ else
30
+ total = 0
31
+ queues.each { |q| total += count(q) }
32
+ total
33
+ end
34
+ end
35
+
36
+ def self.all(offset = 0, limit = 1, queue = :failed, order = 'desc')
37
+ ResqueSqs.list_range(queue, offset, limit, order)
38
+ end
39
+
40
+ def self.queues
41
+ Array(ResqueSqs.redis.smembers(:failed_queues))
42
+ end
43
+
44
+ def self.each(offset = 0, limit = self.count, queue = :failed, class_name = nil, order = 'desc')
45
+ items = all(offset, limit, queue, order)
46
+ items = [items] unless items.is_a? Array
47
+ if order.eql? 'desc'
48
+ items.reverse!
49
+ end
50
+ items.each_with_index do |item, i|
51
+ if !class_name || (item['payload'] && item['payload']['class'] == class_name)
52
+ yield offset + i, item
53
+ end
54
+ end
55
+ end
56
+
57
+ def self.clear(queue = :failed)
58
+ ResqueSqs.redis.del(queue)
59
+ end
60
+
61
+ def self.requeue(id, queue = :failed)
62
+ item = all(id, 1, queue)
63
+ item['retried_at'] = Time.now.strftime("%Y/%m/%d %H:%M:%S")
64
+ ResqueSqs.redis.lset(queue, id, ResqueSqs.encode(item))
65
+ Job.create(item['queue'], item['payload']['class'], *item['payload']['args'])
66
+ end
67
+
68
+ def self.remove(id, queue = :failed)
69
+ sentinel = ""
70
+ ResqueSqs.redis.lset(queue, id, sentinel)
71
+ ResqueSqs.redis.lrem(queue, 1, sentinel)
72
+ end
73
+
74
+ def self.requeue_queue(queue)
75
+ failure_queue = ResqueSqs::Failure.failure_queue_name(queue)
76
+ each(0, count(failure_queue), failure_queue) { |id, _| requeue(id, failure_queue) }
77
+ end
78
+
79
+ def self.remove_queue(queue)
80
+ ResqueSqs.redis.del(ResqueSqs::Failure.failure_queue_name(queue))
81
+ end
82
+
83
+ def filter_backtrace(backtrace)
84
+ index = backtrace.index { |item| item.include?('/lib/resque/job.rb') }
85
+ backtrace.first(index.to_i)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,113 @@
1
+ module ResqueSqs
2
+ # The Failure module provides an interface for working with different
3
+ # failure backends.
4
+ #
5
+ # You can use it to query the failure backend without knowing which specific
6
+ # backend is being used. For instance, the Resque web app uses it to display
7
+ # stats and other information.
8
+ module Failure
9
+ # Creates a new failure, which is delegated to the appropriate backend.
10
+ #
11
+ # Expects a hash with the following keys:
12
+ # :exception - The Exception object
13
+ # :worker - The Worker object who is reporting the failure
14
+ # :queue - The string name of the queue from which the job was pulled
15
+ # :payload - The job's payload
16
+ def self.create(options = {})
17
+ backend.new(*options.values_at(:exception, :worker, :queue, :payload)).save
18
+ end
19
+
20
+ #
21
+ # Sets the current backend. Expects a class descendent of
22
+ # `ResqueSqs::Failure::Base`.
23
+ #
24
+ # Example use:
25
+ # require 'resque_sqs/failure/airbrake'
26
+ # ResqueSqs::Failure.backend = ResqueSqs::Failure::Airbrake
27
+ def self.backend=(backend)
28
+ @backend = backend
29
+ end
30
+
31
+ # Returns the current backend class. If none has been set, falls
32
+ # back to `ResqueSqs::Failure::Redis`
33
+ def self.backend
34
+ return @backend if @backend
35
+
36
+ case ENV['FAILURE_BACKEND']
37
+ when 'redis_multi_queue'
38
+ require 'resque_sqs/failure/redis_multi_queue'
39
+ @backend = Failure::RedisMultiQueue
40
+ when 'redis', nil
41
+ require 'resque_sqs/failure/redis'
42
+ @backend = Failure::Redis
43
+ else
44
+ raise ArgumentError, "invalid failure backend: #{FAILURE_BACKEND}"
45
+ end
46
+ end
47
+
48
+ # Obtain the failure queue name for a given job queue
49
+ def self.failure_queue_name(job_queue_name)
50
+ name = "#{job_queue_name}_failed"
51
+ ResqueSqs.redis.sadd(:failed_queues, name)
52
+ name
53
+ end
54
+
55
+ # Obtain the job queue name for a given failure queue
56
+ def self.job_queue_name(failure_queue_name)
57
+ failure_queue_name.sub(/_failed$/, '')
58
+ end
59
+
60
+ # Returns an array of all the failed queues in the system
61
+ def self.queues
62
+ backend.queues
63
+ end
64
+
65
+ # Returns the int count of how many failures we have seen.
66
+ def self.count(queue = nil, class_name = nil)
67
+ backend.count(queue, class_name)
68
+ end
69
+
70
+ # Returns an array of all the failures, paginated.
71
+ #
72
+ # `offset` is the int of the first item in the page, `limit` is the
73
+ # number of items to return.
74
+ def self.all(offset = 0, limit = 1, queue = nil)
75
+ backend.all(offset, limit, queue)
76
+ end
77
+
78
+ # Iterate across all failures with the given options
79
+ def self.each(offset = 0, limit = self.count, queue = nil, class_name = nil, order = 'desc', &block)
80
+ backend.each(offset, limit, queue, class_name, order, &block)
81
+ end
82
+
83
+ # The string url of the backend's web interface, if any.
84
+ def self.url
85
+ backend.url
86
+ end
87
+
88
+ # Clear all failure jobs
89
+ def self.clear(queue = nil)
90
+ backend.clear(queue)
91
+ end
92
+
93
+ def self.requeue(id)
94
+ backend.requeue(id)
95
+ end
96
+
97
+ def self.remove(id)
98
+ backend.remove(id)
99
+ end
100
+
101
+ # Requeues all failed jobs in a specific queue.
102
+ # Queue name should be a string.
103
+ def self.requeue_queue(queue)
104
+ backend.requeue_queue(queue)
105
+ end
106
+
107
+ # Removes all failed jobs in a specific queue.
108
+ # Queue name should be a string.
109
+ def self.remove_queue(queue)
110
+ backend.remove_queue(queue)
111
+ end
112
+ end
113
+ end