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,238 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'erb'
|
6
|
+
|
7
|
+
require 'active_support/core_ext/hash/keys'
|
8
|
+
require 'active_support/core_ext/hash/deep_merge'
|
9
|
+
|
10
|
+
module Resque
|
11
|
+
module Integration
|
12
|
+
class Configuration
|
13
|
+
# Worker entity
|
14
|
+
class Worker < OpenStruct
|
15
|
+
def initialize(queue, config)
|
16
|
+
data = {:queue => queue}
|
17
|
+
|
18
|
+
if config.is_a?(Hash)
|
19
|
+
data.merge!(config.symbolize_keys)
|
20
|
+
else
|
21
|
+
data[:count] = config
|
22
|
+
end
|
23
|
+
|
24
|
+
super(data)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns workers count for given queue
|
28
|
+
def count
|
29
|
+
[super || 1, 1].max
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns hash of ENV variables that should be associated with this worker
|
33
|
+
def env
|
34
|
+
env = super || {}
|
35
|
+
|
36
|
+
env[:QUEUE] ||= queue
|
37
|
+
env[:JOBS_PER_FORK] ||= jobs_per_fork if jobs_per_fork
|
38
|
+
env[:MINUTES_PER_FORK] ||= minutes_per_fork if minutes_per_fork
|
39
|
+
env[:SHUFFLE] ||= 1 if shuffle
|
40
|
+
|
41
|
+
Hash[env.map { |k, v| [k, v.to_s] }]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Failure notifier configuration
|
46
|
+
class Notifier < OpenStruct
|
47
|
+
def initialize(config)
|
48
|
+
super(config || {})
|
49
|
+
end
|
50
|
+
|
51
|
+
# Is notifier enabled
|
52
|
+
def enabled?
|
53
|
+
to.any? && enabled.nil? ? true : enabled
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns true if payload should be included into reports
|
57
|
+
def include_payload?
|
58
|
+
include_payload.nil? ?
|
59
|
+
true :
|
60
|
+
include_payload
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns recipients list
|
64
|
+
def to
|
65
|
+
super || []
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns sender address
|
69
|
+
def from
|
70
|
+
super || 'no_reply@gmail.com'
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns mailer method
|
74
|
+
def mail
|
75
|
+
(super || :alert).to_sym
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns mailer class
|
79
|
+
def mailer
|
80
|
+
super || 'ResqueFailedJobMailer::Mailer'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Create configuration from given +paths+
|
85
|
+
def initialize(*paths)
|
86
|
+
@configuration = {}
|
87
|
+
paths.each { |f| load f }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns Resque redis configuration
|
91
|
+
#
|
92
|
+
# @return [OpenStruct]
|
93
|
+
def redis
|
94
|
+
@redis ||= (self['redis'] || {}).symbolize_keys
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns workers configuration
|
98
|
+
#
|
99
|
+
# @return [Array<Worker>]
|
100
|
+
def workers
|
101
|
+
@workers ||= (self[:workers] || {}).map { |k, v| Worker.new(k, v) }
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns failure notifier config
|
105
|
+
def failure_notifier
|
106
|
+
@notifier ||= Notifier.new(self['failure.notifier'])
|
107
|
+
end
|
108
|
+
|
109
|
+
# Returns flag for cleaning on shutdown see https://github.com/resque/resque/issues/1167
|
110
|
+
def run_at_exit_hooks?
|
111
|
+
value = self['resque.run_at_exit_hooks']
|
112
|
+
|
113
|
+
if value.is_a?(String) && %w(n no false off disabled).include?(value)
|
114
|
+
value = false
|
115
|
+
end
|
116
|
+
|
117
|
+
value.nil? ? true : value
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns Resque polling interval
|
121
|
+
def interval
|
122
|
+
(self['resque.interval'] || 5).to_i
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns Resque verbosity level
|
126
|
+
def verbosity
|
127
|
+
(self['resque.verbosity'] || 0).to_i
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns Resque log level
|
131
|
+
def log_level
|
132
|
+
(self['resque.log_level'] || 1).to_i
|
133
|
+
end
|
134
|
+
|
135
|
+
# Returns path to resque log file
|
136
|
+
def log_file
|
137
|
+
self['resque.log_file'] || ::Rails.root.join('log/resque.log').to_s
|
138
|
+
end
|
139
|
+
|
140
|
+
def config_file
|
141
|
+
self['resque.config_file'] || ::Rails.root.join('config/resque.god').to_s
|
142
|
+
end
|
143
|
+
|
144
|
+
def pid_file
|
145
|
+
"#{pids}/resque-god.pid"
|
146
|
+
end
|
147
|
+
|
148
|
+
def pids
|
149
|
+
self['resque.pids'] || ::Rails.root.join('tmp/pids').to_s
|
150
|
+
end
|
151
|
+
|
152
|
+
def root
|
153
|
+
self['resque.root'] || ::Rails.root.to_s
|
154
|
+
end
|
155
|
+
|
156
|
+
# Путь до файла с расписание resque schedule
|
157
|
+
#
|
158
|
+
# Returns String
|
159
|
+
def schedule_file
|
160
|
+
self['resque.schedule_file'] || ::Rails.root.join('config', 'resque_schedule.yml')
|
161
|
+
end
|
162
|
+
|
163
|
+
# Есть ли расписание у приложения?
|
164
|
+
#
|
165
|
+
# Returns boolean
|
166
|
+
def schedule_exists?
|
167
|
+
return @schedule_exists if defined?(@schedule_exists)
|
168
|
+
@schedule_exists = File.exist?(schedule_file)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Используется ли resque scheduler
|
172
|
+
#
|
173
|
+
# Returns boolean
|
174
|
+
def resque_scheduler?
|
175
|
+
value = self['resque.scheduler'] || true
|
176
|
+
|
177
|
+
if value.is_a?(String) && %w(n no false off disabled).include?(value)
|
178
|
+
value = false
|
179
|
+
end
|
180
|
+
|
181
|
+
value
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns maximum terminate timeout
|
185
|
+
def terminate_timeout
|
186
|
+
workers.map(&:stop_timeout).compact.max.to_i + 10
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns environment variables that should be associated with this configuration
|
190
|
+
def env
|
191
|
+
env = self['env'] || {}
|
192
|
+
|
193
|
+
env[:INTERVAL] ||= interval
|
194
|
+
|
195
|
+
Hash[env.map { |k, v| [k, v.to_s] }]
|
196
|
+
end
|
197
|
+
|
198
|
+
# Generate GOD configuration file
|
199
|
+
def to_god
|
200
|
+
template = ERB.new(File.read(File.join(File.dirname(__FILE__), 'god.erb')))
|
201
|
+
template.result(binding)
|
202
|
+
end
|
203
|
+
|
204
|
+
def god_log_file
|
205
|
+
self['resque.god_log_file'] || ::Rails.root.join('log/god.log').to_s
|
206
|
+
end
|
207
|
+
|
208
|
+
def god_log_level
|
209
|
+
self['resque.god_log_level'] || 'info'
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
def load(path)
|
214
|
+
if File.exists?(path)
|
215
|
+
input = File.read(path)
|
216
|
+
input = ERB.new(input).result if defined?(ERB)
|
217
|
+
config = YAML.load(input)
|
218
|
+
|
219
|
+
@configuration.merge!(config)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# get value from configuration
|
224
|
+
def [](path)
|
225
|
+
parts = path.to_s.split('.')
|
226
|
+
result = @configuration
|
227
|
+
|
228
|
+
parts.each do |k|
|
229
|
+
result = result[k]
|
230
|
+
|
231
|
+
break if result.nil?
|
232
|
+
end
|
233
|
+
|
234
|
+
result
|
235
|
+
end
|
236
|
+
end # class Configuration
|
237
|
+
end # module Integration
|
238
|
+
end # module Resque
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Resque
|
2
|
+
module Integration
|
3
|
+
# Continuous job can re-enqueue self with respect to resque-lock and resque-meta.
|
4
|
+
#
|
5
|
+
# @example
|
6
|
+
# class ResqueJob
|
7
|
+
# include Resque::Integration
|
8
|
+
#
|
9
|
+
# unique
|
10
|
+
# continuous
|
11
|
+
#
|
12
|
+
# def self.execute(id)
|
13
|
+
# chunk = Company.find(id).products.limit(1000)
|
14
|
+
#
|
15
|
+
# if chunk.size > 0
|
16
|
+
# heavy_work
|
17
|
+
# continue # it will re-enqueue the job with the same arguments. Avoid infinite loops!
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
module Continuous
|
22
|
+
# Remove any locks if needed and re-enqueue job with the same arguments
|
23
|
+
def continue(*args)
|
24
|
+
@continued = args
|
25
|
+
end
|
26
|
+
private :continue # one should not call it from outside
|
27
|
+
|
28
|
+
# This callback resets Meta's finish flags
|
29
|
+
def after_perform_reset_meta(*)
|
30
|
+
if should_reset_meta?
|
31
|
+
meta_obj = meta
|
32
|
+
|
33
|
+
meta_obj.data.delete('succeeded')
|
34
|
+
meta_obj.data.delete('finished_at')
|
35
|
+
|
36
|
+
meta_obj.save
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Just to ensure that previous jobs won't affect current
|
41
|
+
def before_perform_continue(*)
|
42
|
+
@continued = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# `after` callbacks are executed after `around` callbacks
|
46
|
+
# so here we can re-enqueue the job, because lock (from resque-lock) already released
|
47
|
+
def after_perform_continue(*args)
|
48
|
+
if continued?
|
49
|
+
args = if @continued.any?
|
50
|
+
if unique?
|
51
|
+
meta_id = args.first # we should keep meta_id as first argument
|
52
|
+
[meta_id] + @continued
|
53
|
+
else
|
54
|
+
@continued
|
55
|
+
end
|
56
|
+
else
|
57
|
+
args
|
58
|
+
end
|
59
|
+
|
60
|
+
::Resque.enqueue(self, *args)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def continued?
|
67
|
+
!@continued.nil?
|
68
|
+
end
|
69
|
+
|
70
|
+
def should_reset_meta?
|
71
|
+
continued? && unique? && meta
|
72
|
+
end
|
73
|
+
end # module Continuous
|
74
|
+
end # module Integration
|
75
|
+
end # module Resque
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'redis/version'
|
3
|
+
require 'rails/engine'
|
4
|
+
require 'active_support/core_ext/string/inflections'
|
5
|
+
|
6
|
+
module Resque::Integration
|
7
|
+
# Rails engine
|
8
|
+
# @see http://guides.rubyonrails.org/engines.html
|
9
|
+
class Engine < Rails::Engine
|
10
|
+
rake_tasks do
|
11
|
+
load 'resque/integration/tasks/hooks.rake'
|
12
|
+
load 'resque/integration/tasks/resque.rake'
|
13
|
+
load 'resque/integration/tasks/lock.rake'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Читает конфиг-файлы config/resque.yml и config/resque.local.yml,
|
17
|
+
# мерджит результаты и сохраняет в Resque.config
|
18
|
+
initializer 'resque-integration.config' do
|
19
|
+
paths = Rails.root.join('config', 'resque.yml'),
|
20
|
+
Rails.root.join('config', 'resque.local.yml')
|
21
|
+
|
22
|
+
Resque.config = Resque::Integration::Configuration.new(*paths.map(&:to_s))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Читает конфиг-файл config/resque_schedule.yml
|
26
|
+
initializer 'resque-integration.schedule_config' do
|
27
|
+
if Resque.config.resque_scheduler? && Resque.config.schedule_exists?
|
28
|
+
config = ERB.new(File.read(Resque.config.schedule_file)).result
|
29
|
+
Resque.schedule = YAML.load(config)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Устанавливает для Resque соединение с Редисом,
|
34
|
+
# данные берутся из конфига (см. выше)
|
35
|
+
initializer 'resque-integration.redis' do
|
36
|
+
redis = Resque.config.redis
|
37
|
+
|
38
|
+
if redis.any?
|
39
|
+
Resque.redis = Redis.new(redis)
|
40
|
+
Resque.redis.namespace = redis[:namespace] if redis[:namespace]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
initializer 'resque-integration.logger' do
|
45
|
+
Resque.logger.level = Resque.config.log_level
|
46
|
+
|
47
|
+
case Resque.config.verbosity
|
48
|
+
when 1
|
49
|
+
Resque.logger.formatter = Resque::VerboseFormatter.new
|
50
|
+
when 2
|
51
|
+
Resque.logger.formatter = Resque::VeryVerboseFormatter.new
|
52
|
+
else
|
53
|
+
Resque.logger.formatter = Resque::QuietFormatter.new
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Конфигурирование плагина resque-failed-job-mailer.
|
58
|
+
# Данные берутся из конфига (см. выше)
|
59
|
+
initializer 'resque-integration.failure_notifier' do
|
60
|
+
notifier = Resque.config.failure_notifier
|
61
|
+
|
62
|
+
if notifier.enabled?
|
63
|
+
require 'resque_failed_job_mailer'
|
64
|
+
|
65
|
+
Resque::Failure::Notifier.configure do |config|
|
66
|
+
config.to = notifier.to
|
67
|
+
config.from = notifier.from
|
68
|
+
config.include_payload = notifier.include_payload?
|
69
|
+
config.mail = notifier.mail
|
70
|
+
config.mailer = notifier.mailer.constantize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Глушим ошибки, по которым происходит автоматический перезапуск
|
76
|
+
initializer 'resque-integration.retrys' do
|
77
|
+
require 'resque/failure'
|
78
|
+
require 'resque/failure/redis'
|
79
|
+
|
80
|
+
Resque::Failure::MultipleWithRetrySuppression.classes = [
|
81
|
+
Resque::Failure::Redis,
|
82
|
+
Resque::Integration::FailureBackends::QueuesTotals
|
83
|
+
]
|
84
|
+
|
85
|
+
if Resque.config.failure_notifier.enabled?
|
86
|
+
require 'resque_failed_job_mailer'
|
87
|
+
|
88
|
+
Resque::Failure::MultipleWithRetrySuppression.classes << Resque::Failure::Notifier
|
89
|
+
end
|
90
|
+
|
91
|
+
Resque::Failure.backend = Resque::Failure::MultipleWithRetrySuppression
|
92
|
+
end
|
93
|
+
|
94
|
+
initializer "resque-integration.extensions" do
|
95
|
+
::Resque::Worker.prepend ::Resque::Integration::Extensions::Worker
|
96
|
+
::Resque::Job.singleton_class.prepend ::Resque::Integration::Extensions::Job
|
97
|
+
end
|
98
|
+
|
99
|
+
initializer 'resque-integration.application', before: :load_config_initializers do |app|
|
100
|
+
app.config.resque_job_status = {route_constraints: {domain: :current}, route_path: '/_job_'}
|
101
|
+
end
|
102
|
+
end # class Engine
|
103
|
+
end # module Resque::Integration
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Resque
|
2
|
+
module Integration
|
3
|
+
module Extensions
|
4
|
+
# Public: extension for proper determine queue
|
5
|
+
# when destroy job with priority
|
6
|
+
module Job
|
7
|
+
def destroy(queue, klass, *args)
|
8
|
+
if klass.respond_to?(:priority?) && klass.priority?
|
9
|
+
queue = klass.priority_queue(args.last)
|
10
|
+
end
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Resque
|
2
|
+
module Integration
|
3
|
+
module Extensions
|
4
|
+
module Worker
|
5
|
+
def queues
|
6
|
+
queues = super
|
7
|
+
shuffle? ? queues.shuffle : queues
|
8
|
+
end
|
9
|
+
|
10
|
+
def shuffle?
|
11
|
+
return @shuffle if defined?(@shuffle)
|
12
|
+
@shuffle = !ENV['SHUFFLE'].to_s.empty?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Resque
|
2
|
+
module Integration
|
3
|
+
module FailureBackends
|
4
|
+
class QueuesTotals < ::Resque::Failure::Base
|
5
|
+
REDIS_COUNTER_KEY = 'resque:integration:failure_backends:queues_totals'.freeze
|
6
|
+
MAX_COUNTER_VALUE = 10_000_000
|
7
|
+
|
8
|
+
private_constant :REDIS_COUNTER_KEY
|
9
|
+
|
10
|
+
def save
|
11
|
+
current_value = Resque.redis.hincrby(REDIS_COUNTER_KEY, queue, 1)
|
12
|
+
Resque.redis.hset(REDIS_COUNTER_KEY, queue, 1) if current_value >= MAX_COUNTER_VALUE
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.queues
|
16
|
+
Resque.redis.hkeys(REDIS_COUNTER_KEY)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.count(queue = nil, _class_name = nil)
|
20
|
+
if queue.nil?
|
21
|
+
Resque.redis.hvals(REDIS_COUNTER_KEY).map(&:to_i).sum
|
22
|
+
else
|
23
|
+
Resque.redis.hget(REDIS_COUNTER_KEY, queue).to_i
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.clear(queue = nil)
|
28
|
+
if queue.nil?
|
29
|
+
Resque.redis.del(REDIS_COUNTER_KEY)
|
30
|
+
else
|
31
|
+
Resque.redis.hdel(REDIS_COUNTER_KEY, queue)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# THIS FILE IS AUTO-GENERATED. PLEASE DO NOT CHANGE IT!
|
2
|
+
|
3
|
+
bundle = '<%= `which bundle`.strip %>'
|
4
|
+
rails_root = '<%= root %>'
|
5
|
+
God.pid_file_directory = '<%= pids %>'
|
6
|
+
God.terminate_timeout = <%= terminate_timeout.to_i %>
|
7
|
+
|
8
|
+
<% workers.each do |worker| %>
|
9
|
+
<% worker.count.times do |i| %>
|
10
|
+
God.watch do |w|
|
11
|
+
w.dir = rails_root
|
12
|
+
w.name = 'resque-<%= worker.name || worker.queue %>-<%= i %>'
|
13
|
+
w.group = 'resque'
|
14
|
+
w.interval = 30.seconds
|
15
|
+
w.env = <%= Resque.config.env.merge(worker.env).merge(:RAILS_ENV => ::Rails.env, :BUNDLE_GEMFILE => "#{root}/Gemfile").stringify_keys! %>
|
16
|
+
w.start = "#{bundle} exec rake resque:work"
|
17
|
+
w.log = '<%= log_file %>'
|
18
|
+
w.stop_signal = 'QUIT'
|
19
|
+
|
20
|
+
<% if worker.stop_timeout %>
|
21
|
+
w.stop_timeout = <%= worker.stop_timeout %>
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
# determine the state on startup
|
25
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
26
|
+
on.condition(:process_running) do |c|
|
27
|
+
c.running = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# determine when process has finished starting
|
32
|
+
w.transition([:start, :restart], :up) do |on|
|
33
|
+
on.condition(:process_running) do |c|
|
34
|
+
c.running = true
|
35
|
+
c.interval = 5.seconds
|
36
|
+
end
|
37
|
+
|
38
|
+
# failsafe
|
39
|
+
on.condition(:tries) do |c|
|
40
|
+
c.times = 5
|
41
|
+
c.transition = :start
|
42
|
+
c.interval = 5.seconds
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# start if process is not running
|
47
|
+
w.transition(:up, :start) do |on|
|
48
|
+
on.condition(:process_running) do |c|
|
49
|
+
c.running = false
|
50
|
+
end
|
51
|
+
end
|
52
|
+
# END OF WORKER CONFIGURATION
|
53
|
+
end
|
54
|
+
<% end %>
|
55
|
+
<% end %>
|
56
|
+
|
57
|
+
<% if resque_scheduler? %>
|
58
|
+
God.watch do |w|
|
59
|
+
w.dir = rails_root
|
60
|
+
w.name = 'resque-scheduler'
|
61
|
+
w.group = 'resque'
|
62
|
+
w.interval = 30.seconds
|
63
|
+
w.env = <%= Resque.config.env.merge(:RAILS_ENV => ::Rails.env, :BUNDLE_GEMFILE => "#{root}/Gemfile").stringify_keys! %>
|
64
|
+
w.start = "#{bundle} exec rake environment resque:scheduler"
|
65
|
+
w.log = '<%= log_file %>'
|
66
|
+
w.stop_signal = 'QUIT'
|
67
|
+
w.stop_timeout = 60.seconds
|
68
|
+
|
69
|
+
# determine the state on startup
|
70
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
71
|
+
on.condition(:process_running) do |c|
|
72
|
+
c.running = true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# determine when process has finished starting
|
77
|
+
w.transition([:start, :restart], :up) do |on|
|
78
|
+
on.condition(:process_running) do |c|
|
79
|
+
c.running = true
|
80
|
+
c.interval = 5.seconds
|
81
|
+
end
|
82
|
+
|
83
|
+
# failsafe
|
84
|
+
on.condition(:tries) do |c|
|
85
|
+
c.times = 5
|
86
|
+
c.transition = :start
|
87
|
+
c.interval = 5.seconds
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# start if process is not running
|
92
|
+
w.transition(:up, :start) do |on|
|
93
|
+
on.condition(:process_running) do |c|
|
94
|
+
c.running = false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
# END OF SCHEDULE CONFIGURATION
|
98
|
+
end
|
99
|
+
<% end %>
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
module Integration
|
5
|
+
# Backport of resque-1.24.x hooks
|
6
|
+
# @see https://github.com/resque/resque/pull/680/files
|
7
|
+
module Hooks
|
8
|
+
# We do not want to patch Worker, so we declare callable Array
|
9
|
+
class CallableArray < Array
|
10
|
+
def call(*args)
|
11
|
+
each { |hook| hook.call(*args) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
# Call with a block to register a hook.
|
15
|
+
# Call with no arguments to return all registered hooks.
|
16
|
+
def before_first_fork(&block)
|
17
|
+
block ? register_hook(:before_first_fork, block) : hooks(:before_first_fork)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Register a before_first_fork proc.
|
21
|
+
def before_first_fork=(block)
|
22
|
+
register_hook(:before_first_fork, block)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call with a block to register a hook.
|
26
|
+
# Call with no arguments to return all registered hooks.
|
27
|
+
def before_fork(&block)
|
28
|
+
block ? register_hook(:before_fork, block) : hooks(:before_fork)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Register a before_fork proc.
|
32
|
+
def before_fork=(block)
|
33
|
+
register_hook(:before_fork, block)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Call with a block to register a hook.
|
37
|
+
# Call with no arguments to return all registered hooks.
|
38
|
+
def after_fork(&block)
|
39
|
+
block ? register_hook(:after_fork, block) : hooks(:after_fork)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Register an after_fork proc.
|
43
|
+
def after_fork=(block)
|
44
|
+
register_hook(:after_fork, block)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Register a new proc as a hook. If the block is nil this is the
|
50
|
+
# equivalent of removing all hooks of the given name.
|
51
|
+
#
|
52
|
+
# `name` is the hook that the block should be registered with.
|
53
|
+
def register_hook(name, block)
|
54
|
+
return clear_hooks(name) if block.nil?
|
55
|
+
|
56
|
+
@hooks ||= {}
|
57
|
+
@hooks[name] ||= CallableArray.new
|
58
|
+
@hooks[name] << block
|
59
|
+
end
|
60
|
+
|
61
|
+
# Clear all hooks given a hook name.
|
62
|
+
def clear_hooks(name)
|
63
|
+
@hooks && @hooks[name] = CallableArray.new
|
64
|
+
end
|
65
|
+
|
66
|
+
# Retrieve all hooks of a given name.
|
67
|
+
def hooks(name)
|
68
|
+
(@hooks && @hooks[name]) || CallableArray.new
|
69
|
+
end
|
70
|
+
end # module Hooks
|
71
|
+
end # module Integration
|
72
|
+
end # module Resque
|