resque-integration 3.4.1
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/.drone.yml +28 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/Appraisals +27 -0
- data/CHANGELOG.md +311 -0
- data/Gemfile +4 -0
- data/README.md +281 -0
- data/Rakefile +1 -0
- data/app/assets/javascripts/standalone/progress_bar.js +47 -0
- data/app/controllers/resque/jobs_controller.rb +42 -0
- data/app/controllers/resque/queues/info_controller.rb +9 -0
- data/app/controllers/resque/queues/status_controller.rb +38 -0
- data/app/views/shared/job_progress_bar.html.haml +17 -0
- data/bin/resque-status +59 -0
- data/config/routes.rb +13 -0
- data/config.ru +9 -0
- data/dip.yml +44 -0
- data/docker-compose.development.yml +12 -0
- data/docker-compose.drone.yml +6 -0
- data/docker-compose.yml +10 -0
- data/lib/generators/resque/integration/install/install_generator.rb +38 -0
- data/lib/resque/integration/backtrace.rb +29 -0
- data/lib/resque/integration/configuration.rb +238 -0
- data/lib/resque/integration/continuous.rb +75 -0
- data/lib/resque/integration/engine.rb +103 -0
- data/lib/resque/integration/extensions/job.rb +17 -0
- data/lib/resque/integration/extensions/worker.rb +17 -0
- data/lib/resque/integration/extensions.rb +8 -0
- data/lib/resque/integration/failure_backends/queues_totals.rb +37 -0
- data/lib/resque/integration/failure_backends.rb +7 -0
- data/lib/resque/integration/god.erb +99 -0
- data/lib/resque/integration/hooks.rb +72 -0
- data/lib/resque/integration/logs_rotator.rb +95 -0
- data/lib/resque/integration/monkey_patch/verbose_formatter.rb +10 -0
- data/lib/resque/integration/ordered.rb +142 -0
- data/lib/resque/integration/priority.rb +89 -0
- data/lib/resque/integration/queues_info/age.rb +53 -0
- data/lib/resque/integration/queues_info/config.rb +96 -0
- data/lib/resque/integration/queues_info/size.rb +33 -0
- data/lib/resque/integration/queues_info.rb +55 -0
- data/lib/resque/integration/tasks/hooks.rake +49 -0
- data/lib/resque/integration/tasks/lock.rake +37 -0
- data/lib/resque/integration/tasks/resque.rake +101 -0
- data/lib/resque/integration/unique.rb +218 -0
- data/lib/resque/integration/version.rb +5 -0
- data/lib/resque/integration.rb +146 -0
- data/lib/resque-integration.rb +1 -0
- data/resque-integration.gemspec +40 -0
- data/spec/fixtures/resque_queues.yml +45 -0
- data/spec/resque/controllers/jobs_controller_spec.rb +65 -0
- data/spec/resque/integration/configuration_spec.rb +147 -0
- data/spec/resque/integration/continuous_spec.rb +122 -0
- data/spec/resque/integration/failure_backends/queues_totals_spec.rb +105 -0
- data/spec/resque/integration/ordered_spec.rb +87 -0
- data/spec/resque/integration/priority_spec.rb +94 -0
- data/spec/resque/integration/queues_info_spec.rb +402 -0
- data/spec/resque/integration/unique_spec.rb +184 -0
- data/spec/resque/integration_spec.rb +105 -0
- data/spec/shared/resque_inline.rb +10 -0
- data/spec/spec_helper.rb +28 -0
- data/vendor/assets/images/progressbar/white.gif +0 -0
- data/vendor/assets/javascripts/jquery.progressbar.js +177 -0
- data/vendor/assets/stylesheets/jquery.progressbar.css.erb +33 -0
- data/vendor/assets/stylesheets/jquery.progressbar.no_pipeline.css +33 -0
- metadata +402 -0
@@ -0,0 +1,101 @@
|
|
1
|
+
namespace :resque do
|
2
|
+
desc 'Generate God configuration file'
|
3
|
+
task :conf => :environment do
|
4
|
+
File.write(Resque.config.config_file, Resque.config.to_god)
|
5
|
+
|
6
|
+
puts "God configuration file generated to #{Resque.config.config_file}"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc 'Start God server and watch for Resque workers'
|
10
|
+
task :start => :conf do
|
11
|
+
if god_running?
|
12
|
+
puts `#{god} start resque`
|
13
|
+
else
|
14
|
+
puts `#{god} -c #{Resque.config.config_file} -P #{Resque.config.pid_file} --log #{Resque.config.god_log_file} --log-level #{Resque.config.god_log_level} --no-syslog`
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
desc 'Restart Resque workers'
|
19
|
+
task :restart => :conf do
|
20
|
+
if god_stopped?
|
21
|
+
Rake::Task['resque:start'].invoke
|
22
|
+
else
|
23
|
+
puts `#{god} load #{Resque.config.config_file} stop && #{god} restart resque`
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Stop Resque workers'
|
28
|
+
task :stop do
|
29
|
+
puts `#{god} stop resque`
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'Stop Resque workers and quit God'
|
33
|
+
task :terminate do
|
34
|
+
puts `#{god} terminate`
|
35
|
+
end
|
36
|
+
|
37
|
+
desc 'Stop processing any new jobs'
|
38
|
+
task :pause do
|
39
|
+
puts `#{god} signal resque USR2`
|
40
|
+
end
|
41
|
+
|
42
|
+
desc 'Resume jobs processing after pause'
|
43
|
+
task :resume do
|
44
|
+
puts `#{god} signal resque CONT`
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'Shows Resque status'
|
48
|
+
task :status do
|
49
|
+
puts `#{god} status resque`
|
50
|
+
end
|
51
|
+
|
52
|
+
desc 'Установить время истечения resque:resque-retry:*'
|
53
|
+
task :expire => :environment do
|
54
|
+
cursor = 0
|
55
|
+
redis = Redis.current
|
56
|
+
|
57
|
+
loop do
|
58
|
+
cursor, keys = redis.scan(cursor, count: 10_000, match: 'resque:resque-retry:*')
|
59
|
+
cursor = cursor.to_i
|
60
|
+
|
61
|
+
unless keys.empty?
|
62
|
+
redis.pipelined do
|
63
|
+
keys.each { |key| redis.expire(key, 1.hour.seconds) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
break if cursor.zero?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
namespace :logs do
|
72
|
+
desc 'Rotate resque logs'
|
73
|
+
task :rotate => :environment do
|
74
|
+
if god_running?
|
75
|
+
Process.kill('USR1', File.read(Resque.config.pid_file).to_i)
|
76
|
+
sleep 3
|
77
|
+
puts `#{god} signal resque HUP`
|
78
|
+
else
|
79
|
+
puts 'god is not running'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def god
|
87
|
+
`which god`.strip
|
88
|
+
end
|
89
|
+
|
90
|
+
def god_running?
|
91
|
+
File.exists?(Resque.config.pid_file) && Process.kill(0, File.read(Resque.config.pid_file).to_i)
|
92
|
+
rescue Errno::ESRCH
|
93
|
+
false
|
94
|
+
rescue Errno::EPERM
|
95
|
+
true
|
96
|
+
end
|
97
|
+
|
98
|
+
def god_stopped?
|
99
|
+
!god_running?
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'active_support/core_ext/module/aliasing'
|
3
|
+
require 'active_support/core_ext/hash'
|
4
|
+
require 'resque/plugins/progress'
|
5
|
+
|
6
|
+
module Resque
|
7
|
+
module Integration
|
8
|
+
# Unique job
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# class MyJob
|
12
|
+
# include Resque::Integration
|
13
|
+
#
|
14
|
+
# # jobs are considered as equal if their first argument is the same
|
15
|
+
# unique { |*args| args.first }
|
16
|
+
#
|
17
|
+
# def self.execute(image_id)
|
18
|
+
# # do it
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# MyJob.enqueue(11)
|
23
|
+
module Unique
|
24
|
+
LOCK_TIMEOUT = 259_200 # 3 days
|
25
|
+
|
26
|
+
def self.extended(base)
|
27
|
+
if base.singleton_class.include?(::Resque::Integration::Priority)
|
28
|
+
raise 'Uniqueness should be enabled before Prioritness'
|
29
|
+
end
|
30
|
+
|
31
|
+
base.extend(::Resque::Plugins::Progress)
|
32
|
+
base.singleton_class.prepend(Overrides)
|
33
|
+
end
|
34
|
+
|
35
|
+
module Overrides
|
36
|
+
# Overriding +enqueue+ method here so now it returns existing metadata if job already queued
|
37
|
+
def enqueue(*args) #:nodoc:
|
38
|
+
meta = enqueued?(*args)
|
39
|
+
return meta if meta
|
40
|
+
|
41
|
+
# enqueue job and retrieve its meta
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
# Overriding +meta_id+ here so now it generates the same MetaID for Jobs with same args
|
46
|
+
def meta_id(*args)
|
47
|
+
::Digest::SHA1.hexdigest([secret_token, self, lock_on.call(*args)].join)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns true because job is unique now
|
52
|
+
def unique?
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
# Метод вызывает resque-scheduler чтобы поставить задание в текущую очередь
|
57
|
+
def scheduled(queue, klass, *args)
|
58
|
+
klass.constantize.enqueue_to(queue, *args)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Метод вызывает resque-retry когда ставить отложенное задание
|
62
|
+
# здесь мы убираем meta_id из аргументов
|
63
|
+
def retry_args(meta_id, *args)
|
64
|
+
args
|
65
|
+
end
|
66
|
+
|
67
|
+
# Метод вызывает resque-retry, когда записывает/читает число перезапусков
|
68
|
+
# - во время работы воркера первым аргументом передается meta_id;
|
69
|
+
# - во время чтения из вебинтерфейса, meta_id не передается, т.к. она выкидывается во время перепостановки
|
70
|
+
# джоба(см retry_args);
|
71
|
+
# - если метод вызывается в пользовательском коде(и @meta_id отсутствует), то meta_id нельзя передавать.
|
72
|
+
def retry_identifier(*args)
|
73
|
+
return if args.empty?
|
74
|
+
args.shift if @meta_id.is_a?(String) && !@meta_id.empty? && @meta_id == args.first
|
75
|
+
lock_id(*args)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get or set proc returning unique arguments
|
79
|
+
def lock_on(&block)
|
80
|
+
if block_given?
|
81
|
+
@unique = block
|
82
|
+
else
|
83
|
+
@unique ||= proc { |*args| args }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# LockID should be independent from MetaID
|
88
|
+
# @api private
|
89
|
+
def lock_id(*args)
|
90
|
+
args = args.map { |i| i.is_a?(Hash) ? i.with_indifferent_access : i }
|
91
|
+
locked_args = lock_on.call(*args)
|
92
|
+
encoded_args = ::Digest::SHA1.hexdigest(obj_to_string(locked_args))
|
93
|
+
"lock:#{name}-#{encoded_args}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# get meta object associated with job
|
97
|
+
def meta
|
98
|
+
get_meta(@meta_id)
|
99
|
+
end
|
100
|
+
|
101
|
+
# default `perform` method override
|
102
|
+
def perform(meta_id, *args)
|
103
|
+
execute(*args)
|
104
|
+
end
|
105
|
+
|
106
|
+
def execute(*)
|
107
|
+
raise NotImplementedError, "You should implement `execute' method"
|
108
|
+
end
|
109
|
+
|
110
|
+
# When job is failed we should remove lock
|
111
|
+
def on_failure_lock(_e, _meta_id, *args)
|
112
|
+
unlock(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Before dequeue check if job is running
|
116
|
+
def before_dequeue_lock(*args)
|
117
|
+
(meta_id = args.first) &&
|
118
|
+
(meta = get_meta(meta_id)) &&
|
119
|
+
!meta.working?
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_failure_retry(exception, *args)
|
123
|
+
return unless defined?(super)
|
124
|
+
|
125
|
+
# Keep meta_id if kill -9 (or ABRT)
|
126
|
+
@meta_id = args.first if exception.is_a?(::Resque::DirtyExit)
|
127
|
+
|
128
|
+
super
|
129
|
+
end
|
130
|
+
|
131
|
+
# Before enqueue acquire a lock
|
132
|
+
#
|
133
|
+
# Returns boolean
|
134
|
+
def before_enqueue_lock(_meta_id, *args)
|
135
|
+
::Resque.redis.set(lock_id(*args), 1, ex: lock_timeout, nx: true)
|
136
|
+
end
|
137
|
+
|
138
|
+
def around_perform_lock(_meta_id, *args)
|
139
|
+
yield
|
140
|
+
ensure
|
141
|
+
# Always clear the lock when we're done, even if there is an error.
|
142
|
+
unlock(*args)
|
143
|
+
end
|
144
|
+
|
145
|
+
# When job is dequeued we should remove lock
|
146
|
+
def after_dequeue_lock(_meta_id, *args)
|
147
|
+
unlock(*args) unless args.empty?
|
148
|
+
end
|
149
|
+
|
150
|
+
# Fail metadata if dequeue succeed
|
151
|
+
def after_dequeue_meta(*args)
|
152
|
+
if (meta_id = args.first) && (meta = get_meta(meta_id))
|
153
|
+
meta.fail!
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Is job already in queue or in process?
|
158
|
+
def enqueued?(*args)
|
159
|
+
# if lock exists and timeout not exceeded
|
160
|
+
get_meta(meta_id(*args)) if locked?(*args)
|
161
|
+
end
|
162
|
+
|
163
|
+
def lock_timeout
|
164
|
+
LOCK_TIMEOUT
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns true if resque job is in locked state
|
168
|
+
def locked?(*args)
|
169
|
+
::Resque.redis.exists(lock_id(*args))
|
170
|
+
end
|
171
|
+
|
172
|
+
# Dequeue unique job
|
173
|
+
def dequeue(*args)
|
174
|
+
::Resque.dequeue(self, meta_id(*args), *args)
|
175
|
+
end
|
176
|
+
|
177
|
+
def enqueue_to(queue, *args)
|
178
|
+
meta = enqueued?(*args)
|
179
|
+
return meta if meta.present?
|
180
|
+
|
181
|
+
meta = ::Resque::Plugins::Meta::Metadata.new('meta_id' => meta_id(args), 'job_class' => to_s)
|
182
|
+
meta.save
|
183
|
+
|
184
|
+
::Resque.enqueue_to(queue, self, meta.meta_id, *args)
|
185
|
+
meta
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
# Remove lock for job with given +args+
|
191
|
+
def unlock(*args)
|
192
|
+
::Resque.redis.del(lock_id(*args))
|
193
|
+
end
|
194
|
+
|
195
|
+
def secret_token
|
196
|
+
::Rails.respond_to?(:application) &&
|
197
|
+
::Rails.application &&
|
198
|
+
::Rails.application.config.secret_token
|
199
|
+
end
|
200
|
+
|
201
|
+
def obj_to_string(obj)
|
202
|
+
case obj
|
203
|
+
when Hash
|
204
|
+
s = []
|
205
|
+
obj.keys.sort.each do |k|
|
206
|
+
s << obj_to_string(k)
|
207
|
+
s << obj_to_string(obj[k])
|
208
|
+
end
|
209
|
+
s.to_s
|
210
|
+
when Array
|
211
|
+
obj.map { |a| obj_to_string(a) }.to_s
|
212
|
+
else
|
213
|
+
obj.to_s
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end # module Unique
|
217
|
+
end # module Integration
|
218
|
+
end # module Resque
|
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'resque/integration/version'
|
2
|
+
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'rails/railtie'
|
5
|
+
require 'active_record'
|
6
|
+
require 'action_pack'
|
7
|
+
|
8
|
+
require 'rake'
|
9
|
+
require 'multi_json'
|
10
|
+
|
11
|
+
require 'resque'
|
12
|
+
silence_warnings { require 'resque/plugins/meta' }
|
13
|
+
|
14
|
+
require 'resque/integration/monkey_patch/verbose_formatter'
|
15
|
+
require 'resque/integration/hooks'
|
16
|
+
|
17
|
+
require 'resque/scheduler'
|
18
|
+
require 'resque/scheduler/tasks'
|
19
|
+
require 'resque-retry'
|
20
|
+
|
21
|
+
module Resque
|
22
|
+
include Integration::Hooks
|
23
|
+
extend Integration::Hooks
|
24
|
+
|
25
|
+
# Resque.config is available now
|
26
|
+
mattr_accessor :config
|
27
|
+
|
28
|
+
def queues_info
|
29
|
+
return @queues_info if defined?(@queues_info)
|
30
|
+
|
31
|
+
queues_info_config = Rails.root.join('config', 'resque_queues.yml')
|
32
|
+
|
33
|
+
@queues_info = Resque::Integration::QueuesInfo.new(config: queues_info_config)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Seamless resque integration with all necessary plugins
|
37
|
+
# You should define an +execute+ method (not +perform+)
|
38
|
+
#
|
39
|
+
# Usage:
|
40
|
+
# class MyJob
|
41
|
+
# include Resque::Integration
|
42
|
+
#
|
43
|
+
# queue :my_queue
|
44
|
+
# unique ->(*args) { args.first }
|
45
|
+
|
46
|
+
# def self.execute(*args)
|
47
|
+
# end
|
48
|
+
# end
|
49
|
+
module Integration
|
50
|
+
autoload :Backtrace, 'resque/integration/backtrace'
|
51
|
+
autoload :CLI, 'resque/integration/cli'
|
52
|
+
autoload :Configuration, 'resque/integration/configuration'
|
53
|
+
autoload :Continuous, 'resque/integration/continuous'
|
54
|
+
autoload :Unique, 'resque/integration/unique'
|
55
|
+
autoload :Ordered, 'resque/integration/ordered'
|
56
|
+
autoload :LogsRotator, 'resque/integration/logs_rotator'
|
57
|
+
autoload :QueuesInfo, 'resque/integration/queues_info'
|
58
|
+
autoload :Extensions, 'resque/integration/extensions'
|
59
|
+
autoload :FailureBackends, 'resque/integration/failure_backends'
|
60
|
+
autoload :Priority, 'resque/integration/priority'
|
61
|
+
|
62
|
+
extend ActiveSupport::Concern
|
63
|
+
|
64
|
+
included do
|
65
|
+
extend Backtrace
|
66
|
+
|
67
|
+
@queue ||= :default
|
68
|
+
end
|
69
|
+
|
70
|
+
module ClassMethods
|
71
|
+
# Get or set queue name (just a synonym to resque native methodology)
|
72
|
+
def queue(name = nil)
|
73
|
+
if name
|
74
|
+
@queue = name
|
75
|
+
else
|
76
|
+
@queue
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Mark Job as unique and set given +callback+ or +block+ as Unique Arguments procedure
|
81
|
+
def unique(callback = nil, &block)
|
82
|
+
extend Unique unless unique?
|
83
|
+
|
84
|
+
lock_on(&(callback || block))
|
85
|
+
end
|
86
|
+
|
87
|
+
# Extend job with 'continuous' functionality so you can re-enqueue job with +continue+ method.
|
88
|
+
def continuous
|
89
|
+
extend Continuous
|
90
|
+
end
|
91
|
+
|
92
|
+
def unique?
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: job used priority queues
|
97
|
+
def priority?
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
# Extend resque-retry.
|
102
|
+
#
|
103
|
+
# options - Hash
|
104
|
+
#
|
105
|
+
# :limit - Integer (default: 2)
|
106
|
+
# :delay - Integer (default: 60)
|
107
|
+
# :expire_retry_key_after - Integer (default: 3200), истечение ключа в секундах. Если
|
108
|
+
#
|
109
|
+
# t - среднее время выполнения одного джоба
|
110
|
+
# n - текущее кол-во джобов в очереди
|
111
|
+
# k - кол-во воркеров
|
112
|
+
#
|
113
|
+
# то expire_retry_key_after >= t * n / k
|
114
|
+
#
|
115
|
+
# Иначе ключ истечет, прежде чем джоб отработает.
|
116
|
+
#
|
117
|
+
#
|
118
|
+
# Returns nothing
|
119
|
+
def retrys(options = {})
|
120
|
+
if unique?
|
121
|
+
raise '`retrys` should be declared higher in code than `unique`'
|
122
|
+
end
|
123
|
+
|
124
|
+
extend Resque::Plugins::Retry
|
125
|
+
|
126
|
+
@retry_limit = options.fetch(:limit, 2)
|
127
|
+
@retry_delay = options.fetch(:delay, 60)
|
128
|
+
@expire_retry_key_after = options.fetch(:expire_retry_key_after, 1.hour.seconds)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Mark Job as ordered
|
132
|
+
def ordered(options = {})
|
133
|
+
extend Ordered
|
134
|
+
|
135
|
+
self.max_iterations = options.fetch(:max_iterations, 20)
|
136
|
+
self.uniqueness = Ordered::Uniqueness.new(&options[:unique]) if options.key?(:unique)
|
137
|
+
end
|
138
|
+
|
139
|
+
def prioritized
|
140
|
+
extend Priority
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end # module Integration
|
144
|
+
end # module Resque
|
145
|
+
|
146
|
+
require 'resque/integration/engine'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'resque/integration'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'resque/integration/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.name = 'resque-integration'
|
7
|
+
gem.version = Resque::Integration::VERSION
|
8
|
+
gem.authors = ['Alexei Mikhailov', 'Michail Merkushin']
|
9
|
+
gem.email = %w(amikhailov83@gmail.com merkushin.m.s@gmail.com)
|
10
|
+
gem.summary = %q{Seamless integration of resque with resque-progress and resque-lock}
|
11
|
+
gem.homepage = 'https://github.com/abak-press/resque-integration'
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($/)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = %w(lib)
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'resque', '>= 1.25.2'
|
19
|
+
gem.add_runtime_dependency 'rails', '>= 3.0.0'
|
20
|
+
gem.add_runtime_dependency 'resque-meta', '>= 2.0.0'
|
21
|
+
gem.add_runtime_dependency 'resque-progress', '~> 1.0.1'
|
22
|
+
gem.add_runtime_dependency 'resque-multi-job-forks', '~> 0.4.2'
|
23
|
+
gem.add_runtime_dependency 'resque-failed-job-mailer', '~> 0.0.3'
|
24
|
+
gem.add_runtime_dependency 'resque-scheduler', '~> 4.0'
|
25
|
+
gem.add_runtime_dependency 'resque-retry', '~> 1.5'
|
26
|
+
gem.add_runtime_dependency 'god', '~> 0.13.4'
|
27
|
+
|
28
|
+
gem.add_runtime_dependency 'multi_json'
|
29
|
+
gem.add_runtime_dependency 'rake'
|
30
|
+
|
31
|
+
gem.add_development_dependency 'bundler'
|
32
|
+
gem.add_development_dependency 'rspec', '~> 2.14'
|
33
|
+
gem.add_development_dependency 'rspec-its'
|
34
|
+
gem.add_development_dependency 'simplecov'
|
35
|
+
gem.add_development_dependency 'appraisal', '>= 1.0.2'
|
36
|
+
gem.add_development_dependency 'combustion', '>= 0.5.5'
|
37
|
+
gem.add_development_dependency 'mock_redis'
|
38
|
+
gem.add_development_dependency 'timecop'
|
39
|
+
gem.add_development_dependency 'pry-byebug'
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
defaults:
|
2
|
+
max_age: 10
|
3
|
+
max_size: 10
|
4
|
+
max_failures_count_per_5m: 5
|
5
|
+
max_failures_count_per_1h: 60
|
6
|
+
channel: default
|
7
|
+
|
8
|
+
warn_age: 8
|
9
|
+
warn_size: 7
|
10
|
+
warn_failures_count_per_5m: 3
|
11
|
+
warn_failures_count_per_1h: 30
|
12
|
+
warn_channel: default_warnings
|
13
|
+
|
14
|
+
queues:
|
15
|
+
?
|
16
|
+
>
|
17
|
+
first,
|
18
|
+
third
|
19
|
+
:
|
20
|
+
max_age: 20
|
21
|
+
warn_age: 10
|
22
|
+
|
23
|
+
max_size: 100
|
24
|
+
warn_size: 50
|
25
|
+
|
26
|
+
max_failures_count_per_5m: 15
|
27
|
+
warn_failures_count_per_5m: 7
|
28
|
+
|
29
|
+
max_failures_count_per_1h: 90
|
30
|
+
warn_failures_count_per_1h: 45
|
31
|
+
|
32
|
+
channel: first
|
33
|
+
warn_channel: first_warnings
|
34
|
+
|
35
|
+
third:
|
36
|
+
max_age: 30
|
37
|
+
warn_age: 15
|
38
|
+
max_failures_count_per_1h: 70
|
39
|
+
warn_failures_count_per_1h: 35
|
40
|
+
|
41
|
+
second_queue:
|
42
|
+
channel: [first, second]
|
43
|
+
warn_channel: [first_warnings, second_warnings]
|
44
|
+
|
45
|
+
without_channel: {}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Resque::JobsController do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
class MetaJob
|
7
|
+
extend Resque::Plugins::Meta
|
8
|
+
|
9
|
+
@queue = 'test'
|
10
|
+
|
11
|
+
def self.perform(_meta_id); end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#show' do
|
15
|
+
let(:app) { described_class.action(:show) }
|
16
|
+
|
17
|
+
context 'when id is missing' do
|
18
|
+
before do
|
19
|
+
get '/'
|
20
|
+
end
|
21
|
+
|
22
|
+
it do
|
23
|
+
expect(last_response.status).to eq 404
|
24
|
+
expect(last_response.body).to eq '{"message":"not found"}'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'when id is invalid' do
|
29
|
+
before do
|
30
|
+
get '/', id: 'xx'
|
31
|
+
end
|
32
|
+
|
33
|
+
it do
|
34
|
+
expect(last_response.status).to eq 404
|
35
|
+
expect(last_response.body).to eq '{"message":"not found"}'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when id is correct' do
|
40
|
+
let(:meta) { MetaJob.enqueue }
|
41
|
+
let(:meta_id) { meta.meta_id }
|
42
|
+
let(:body) do
|
43
|
+
{
|
44
|
+
enqueued_at: meta.enqueued_at,
|
45
|
+
started_at: nil,
|
46
|
+
finished_at: nil,
|
47
|
+
succeeded: nil,
|
48
|
+
failed: nil,
|
49
|
+
progress: {num: 0, total: 1, percent: 0.0, message: nil},
|
50
|
+
payload: nil
|
51
|
+
}.to_json
|
52
|
+
end
|
53
|
+
|
54
|
+
before do
|
55
|
+
get '/', id: meta_id
|
56
|
+
end
|
57
|
+
|
58
|
+
it do
|
59
|
+
expect(last_response.status).to eq 200
|
60
|
+
expect(last_response.body).to eq body
|
61
|
+
expect(last_response['Cache-Control']).to eq 'no-cache'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|