resque-integration 3.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|