heroku-resque-pool 0.0.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/LICENSE.txt +20 -0
- data/README.md +2 -0
- data/Rakefile +37 -0
- data/bin/heroku-resque-pool +7 -0
- data/lib/resque/pool.rb +446 -0
- data/lib/resque/pool/cli.rb +184 -0
- data/lib/resque/pool/file_or_hash_loader.rb +59 -0
- data/lib/resque/pool/killer.rb +40 -0
- data/lib/resque/pool/logging.rb +124 -0
- data/lib/resque/pool/pooled_worker.rb +41 -0
- data/lib/resque/pool/tasks.rb +20 -0
- data/lib/resque/pool/version.rb +5 -0
- data/man/resque-pool.1 +88 -0
- data/man/resque-pool.1.ronn +92 -0
- data/man/resque-pool.yml.5 +46 -0
- data/man/resque-pool.yml.5.ronn +41 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ebae8d33e9ac962bd6900f82137f77316081223b
|
4
|
+
data.tar.gz: 5d45c9065c5c0d2e9bb1a0932db1b5ecaf56ccaa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 595892e90edfd1fe375555c6b72f027e94c207338815643d1c87972b8e51e2158aec290f134b558d480d45950788a82c0cecd7f2121a938f766d58534781cb5a
|
7
|
+
data.tar.gz: e8d5a3dd5f1fcbe54aab6a304149eb15698e0a8ef2b235cbfa874b2fee0e754ad90ecf52f723fdf435bb01e9142807f53d54d280e1602595e829ca66df022353
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (C) 2010 by Nicholas Evans <nick@ekenosen.net>, et al.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
|
+
# for loading the example config file in config/resque-pool.yml
|
5
|
+
require 'resque/pool/tasks'
|
6
|
+
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
desc "Run fast RSpec code examples"
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
11
|
+
t.rspec_opts = ["-c", "-f progress", "--tag ~slow"]
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Run all RSpec code examples"
|
15
|
+
RSpec::Core::RakeTask.new("spec:ci") do |t|
|
16
|
+
t.rspec_opts = ["-c", "-f progress"]
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'cucumber/rake/task'
|
20
|
+
Cucumber::Rake::Task.new(:features) do |c|
|
21
|
+
c.profile = "rake"
|
22
|
+
end
|
23
|
+
|
24
|
+
task :default => ["spec:ci", :features]
|
25
|
+
|
26
|
+
rule(/\.[1-9]$/ => [proc { |tn| "#{tn}.ronn" }]) do |t|
|
27
|
+
name = Resque::Pool.name.sub('::','-').upcase
|
28
|
+
version = "%s %s" % [name, Resque::Pool::VERSION.upcase]
|
29
|
+
|
30
|
+
manual = '--manual "%s"' % name
|
31
|
+
organization = '--organization "%s"' % version
|
32
|
+
sh "ronn #{manual} #{organization} <#{t.source} >#{t.name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
file 'man/resque-pool.1'
|
36
|
+
file 'man/resque-pool.yml.5'
|
37
|
+
task :manpages => ['man/resque-pool.1','man/resque-pool.yml.5']
|
data/lib/resque/pool.rb
ADDED
@@ -0,0 +1,446 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'resque'
|
3
|
+
require 'resque/worker'
|
4
|
+
require 'resque/pool/version'
|
5
|
+
require 'resque/pool/logging'
|
6
|
+
require 'resque/pool/pooled_worker'
|
7
|
+
require 'resque/pool/file_or_hash_loader'
|
8
|
+
require 'erb'
|
9
|
+
require 'fcntl'
|
10
|
+
require 'yaml'
|
11
|
+
|
12
|
+
module Resque
|
13
|
+
class Pool
|
14
|
+
SIG_QUEUE_MAX_SIZE = 5
|
15
|
+
DEFAULT_WORKER_INTERVAL = 5
|
16
|
+
QUEUE_SIGS = [ :QUIT, :INT, :TERM, :USR1, :USR2, :CONT, :HUP, :WINCH, ]
|
17
|
+
CHUNK_SIZE = (16 * 1024)
|
18
|
+
|
19
|
+
include Logging
|
20
|
+
extend Logging
|
21
|
+
attr_reader :config
|
22
|
+
attr_reader :config_loader
|
23
|
+
attr_reader :workers
|
24
|
+
|
25
|
+
def initialize(config_loader=nil)
|
26
|
+
init_config(config_loader)
|
27
|
+
@workers = Hash.new { |workers, queues| workers[queues] = {} }
|
28
|
+
procline "(initialized)"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Config: hooks {{{
|
32
|
+
|
33
|
+
def self.hook(name) # :nodoc:
|
34
|
+
class_eval <<-CODE
|
35
|
+
def self.#{name}(&block)
|
36
|
+
@#{name} ||= []
|
37
|
+
block ? (@#{name} << block) : @#{name}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.#{name}=(block)
|
41
|
+
@#{name} = [block]
|
42
|
+
end
|
43
|
+
|
44
|
+
def call_#{name}!(*args)
|
45
|
+
self.class.#{name}.each do |hook|
|
46
|
+
hook.call(*args)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
CODE
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# :call-seq:
|
54
|
+
# after_prefork do |worker| ... end => add a hook
|
55
|
+
# after_prefork << hook => add a hook
|
56
|
+
#
|
57
|
+
# +after_prefork+ will run in workers before any jobs. Use these hooks e.g.
|
58
|
+
# to reload database connections to ensure that they're not shared among
|
59
|
+
# workers.
|
60
|
+
#
|
61
|
+
# :yields: worker
|
62
|
+
hook :after_prefork
|
63
|
+
|
64
|
+
##
|
65
|
+
# :call-seq:
|
66
|
+
# after_prefork do |worker, pid, workers| ... end => add a hook
|
67
|
+
# after_prefork << hook => add a hook
|
68
|
+
#
|
69
|
+
# The `after_spawn` hooks will run in the master after spawning a new
|
70
|
+
# worker.
|
71
|
+
#
|
72
|
+
# :yields: worker, pid, workers
|
73
|
+
hook :after_spawn
|
74
|
+
|
75
|
+
# }}}
|
76
|
+
# Config: class methods to start up the pool using the config loader {{{
|
77
|
+
|
78
|
+
class << self; attr_accessor :config_loader, :app_name, :spawn_delay; end
|
79
|
+
|
80
|
+
def self.app_name
|
81
|
+
@app_name ||= File.basename(Dir.pwd)
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.handle_winch?
|
85
|
+
@handle_winch ||= false
|
86
|
+
end
|
87
|
+
def self.handle_winch=(bool)
|
88
|
+
@handle_winch = bool
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.kill_other_pools!
|
92
|
+
require 'resque/pool/killer'
|
93
|
+
Resque::Pool::Killer.run
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.single_process_group=(bool)
|
97
|
+
ENV["RESQUE_SINGLE_PGRP"] = !!bool ? "YES" : "NO"
|
98
|
+
end
|
99
|
+
def self.single_process_group
|
100
|
+
%w[yes y true t 1 okay sure please].include?(
|
101
|
+
ENV["RESQUE_SINGLE_PGRP"].to_s.downcase
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.run
|
106
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
107
|
+
GC.copy_on_write_friendly = true
|
108
|
+
end
|
109
|
+
create_configured.start.join
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.create_configured
|
113
|
+
Resque::Pool.new(config_loader)
|
114
|
+
end
|
115
|
+
|
116
|
+
# }}}
|
117
|
+
# Config: store loader and load config {{{
|
118
|
+
|
119
|
+
def init_config(loader)
|
120
|
+
case loader
|
121
|
+
when String, Hash, nil
|
122
|
+
@config_loader = FileOrHashLoader.new(loader)
|
123
|
+
else
|
124
|
+
@config_loader = loader
|
125
|
+
end
|
126
|
+
load_config
|
127
|
+
end
|
128
|
+
|
129
|
+
def load_config
|
130
|
+
@config = config_loader.call(environment)
|
131
|
+
end
|
132
|
+
|
133
|
+
def reset_config
|
134
|
+
config_loader.reset! if config_loader.respond_to?(:reset!)
|
135
|
+
load_config
|
136
|
+
end
|
137
|
+
|
138
|
+
def environment
|
139
|
+
if defined? RAILS_ENV
|
140
|
+
RAILS_ENV
|
141
|
+
elsif defined?(Rails) && Rails.respond_to?(:env)
|
142
|
+
Rails.env
|
143
|
+
else
|
144
|
+
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || ENV['RESQUE_ENV']
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# }}}
|
149
|
+
|
150
|
+
# Sig handlers and self pipe management {{{
|
151
|
+
|
152
|
+
def self_pipe; @self_pipe ||= [] end
|
153
|
+
def sig_queue; @sig_queue ||= [] end
|
154
|
+
def term_child; @term_child ||= ENV['TERM_CHILD'] end
|
155
|
+
|
156
|
+
|
157
|
+
def init_self_pipe!
|
158
|
+
self_pipe.each { |io| io.close rescue nil }
|
159
|
+
self_pipe.replace(IO.pipe)
|
160
|
+
self_pipe.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
161
|
+
end
|
162
|
+
|
163
|
+
def init_sig_handlers!
|
164
|
+
QUEUE_SIGS.each { |sig| trap_deferred(sig) }
|
165
|
+
trap(:CHLD) { |_| awaken_master }
|
166
|
+
end
|
167
|
+
|
168
|
+
def awaken_master
|
169
|
+
begin
|
170
|
+
self_pipe.last.write_nonblock('.') # wakeup master process from select
|
171
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
172
|
+
# pipe is full, master should wake up anyways
|
173
|
+
retry
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class QuitNowException < Exception; end
|
178
|
+
# defer a signal for later processing in #join (master process)
|
179
|
+
def trap_deferred(signal)
|
180
|
+
trap(signal) do |sig_nr|
|
181
|
+
if @waiting_for_reaper && [:INT, :TERM].include?(signal)
|
182
|
+
log "Recieved #{signal}: short circuiting QUIT waitpid"
|
183
|
+
raise QuitNowException
|
184
|
+
end
|
185
|
+
if sig_queue.size < SIG_QUEUE_MAX_SIZE
|
186
|
+
sig_queue << signal
|
187
|
+
awaken_master
|
188
|
+
else
|
189
|
+
log "ignoring SIG#{signal}, queue=#{sig_queue.inspect}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def reset_sig_handlers!
|
195
|
+
QUEUE_SIGS.each {|sig| trap(sig, "DEFAULT") }
|
196
|
+
end
|
197
|
+
|
198
|
+
def handle_sig_queue!
|
199
|
+
case signal = sig_queue.shift
|
200
|
+
when :USR1, :USR2, :CONT
|
201
|
+
log "#{signal}: sending to all workers"
|
202
|
+
signal_all_workers(signal)
|
203
|
+
when :HUP
|
204
|
+
log "HUP: reset configuration and reload logfiles"
|
205
|
+
reset_config
|
206
|
+
Logging.reopen_logs!
|
207
|
+
log "HUP: gracefully shutdown old children (which have old logfiles open)"
|
208
|
+
if term_child
|
209
|
+
signal_all_workers(:TERM)
|
210
|
+
else
|
211
|
+
signal_all_workers(:QUIT)
|
212
|
+
end
|
213
|
+
log "HUP: new children will inherit new logfiles"
|
214
|
+
maintain_worker_count
|
215
|
+
when :WINCH
|
216
|
+
if self.class.handle_winch?
|
217
|
+
log "WINCH: gracefully stopping all workers"
|
218
|
+
@config = {}
|
219
|
+
maintain_worker_count
|
220
|
+
end
|
221
|
+
when :QUIT
|
222
|
+
if term_child
|
223
|
+
shutdown_everything_now!(signal)
|
224
|
+
else
|
225
|
+
graceful_worker_shutdown_and_wait!(signal)
|
226
|
+
end
|
227
|
+
when :INT
|
228
|
+
graceful_worker_shutdown!(signal)
|
229
|
+
when :TERM
|
230
|
+
case self.class.term_behavior
|
231
|
+
when "graceful_worker_shutdown_and_wait"
|
232
|
+
graceful_worker_shutdown_and_wait!(signal)
|
233
|
+
when "graceful_worker_shutdown"
|
234
|
+
graceful_worker_shutdown!(signal)
|
235
|
+
else
|
236
|
+
shutdown_everything_now!(signal)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class << self
|
242
|
+
attr_accessor :term_behavior
|
243
|
+
attr_accessor :kill_other_pools
|
244
|
+
end
|
245
|
+
|
246
|
+
def graceful_worker_shutdown_and_wait!(signal)
|
247
|
+
log "#{signal}: graceful shutdown, waiting for children"
|
248
|
+
if term_child
|
249
|
+
signal_all_workers(:TERM)
|
250
|
+
else
|
251
|
+
signal_all_workers(:QUIT)
|
252
|
+
end
|
253
|
+
reap_all_workers(0) # will hang until all workers are shutdown
|
254
|
+
:break
|
255
|
+
end
|
256
|
+
|
257
|
+
def graceful_worker_shutdown!(signal)
|
258
|
+
log "#{signal}: immediate shutdown (graceful worker shutdown)"
|
259
|
+
if term_child
|
260
|
+
signal_all_workers(:TERM)
|
261
|
+
else
|
262
|
+
signal_all_workers(:QUIT)
|
263
|
+
end
|
264
|
+
:break
|
265
|
+
end
|
266
|
+
|
267
|
+
def shutdown_everything_now!(signal)
|
268
|
+
log "#{signal}: immediate shutdown (and immediate worker shutdown)"
|
269
|
+
if term_child
|
270
|
+
signal_all_workers(:QUIT)
|
271
|
+
else
|
272
|
+
signal_all_workers(:TERM)
|
273
|
+
end
|
274
|
+
:break
|
275
|
+
end
|
276
|
+
|
277
|
+
# }}}
|
278
|
+
# start, join, and master sleep {{{
|
279
|
+
|
280
|
+
def start
|
281
|
+
procline("(starting)")
|
282
|
+
init_self_pipe!
|
283
|
+
init_sig_handlers!
|
284
|
+
maintain_worker_count
|
285
|
+
procline("(started)")
|
286
|
+
log "started manager"
|
287
|
+
report_worker_pool_pids
|
288
|
+
self.class.kill_other_pools! if self.class.kill_other_pools
|
289
|
+
self
|
290
|
+
end
|
291
|
+
|
292
|
+
def report_worker_pool_pids
|
293
|
+
if workers.empty?
|
294
|
+
log "Pool is empty"
|
295
|
+
else
|
296
|
+
log "Pool contains worker PIDs: #{all_pids.inspect}"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def join
|
301
|
+
loop do
|
302
|
+
reap_all_workers
|
303
|
+
break if handle_sig_queue! == :break
|
304
|
+
if sig_queue.empty?
|
305
|
+
master_sleep
|
306
|
+
load_config
|
307
|
+
maintain_worker_count
|
308
|
+
end
|
309
|
+
procline("managing #{all_pids.inspect}")
|
310
|
+
end
|
311
|
+
procline("(shutting down)")
|
312
|
+
#stop # gracefully shutdown all workers on our way out
|
313
|
+
log "manager finished"
|
314
|
+
#unlink_pid_safe(pid) if pid
|
315
|
+
end
|
316
|
+
|
317
|
+
def master_sleep
|
318
|
+
begin
|
319
|
+
ready = IO.select([self_pipe.first], nil, nil, 1) or return
|
320
|
+
ready.first && ready.first.first or return
|
321
|
+
loop { self_pipe.first.read_nonblock(CHUNK_SIZE) }
|
322
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
# }}}
|
327
|
+
# worker process management {{{
|
328
|
+
|
329
|
+
def reap_all_workers(waitpid_flags=Process::WNOHANG)
|
330
|
+
@waiting_for_reaper = waitpid_flags == 0
|
331
|
+
begin
|
332
|
+
loop do
|
333
|
+
# -1, wait for any child process
|
334
|
+
wpid, status = Process.waitpid2(-1, waitpid_flags)
|
335
|
+
break unless wpid
|
336
|
+
|
337
|
+
if worker = delete_worker(wpid)
|
338
|
+
log "Reaped resque worker[#{status.pid}] (status: #{status.exitstatus}) queues: #{worker.queues.join(",")}"
|
339
|
+
else
|
340
|
+
# this died before it could be killed, so it's not going to have any extra info
|
341
|
+
log "Tried to reap worker [#{status.pid}], but it had already died. (status: #{status.exitstatus})"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
rescue Errno::ECHILD, QuitNowException
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# TODO: close any file descriptors connected to worker, if any
|
349
|
+
def delete_worker(pid)
|
350
|
+
worker = nil
|
351
|
+
workers.detect do |queues, pid_to_worker|
|
352
|
+
worker = pid_to_worker.delete(pid)
|
353
|
+
end
|
354
|
+
worker
|
355
|
+
end
|
356
|
+
|
357
|
+
def all_pids
|
358
|
+
workers.map {|q,workers| workers.keys }.flatten
|
359
|
+
end
|
360
|
+
|
361
|
+
def signal_all_workers(signal)
|
362
|
+
log "Sending #{signal} to all workers"
|
363
|
+
all_pids.each do |pid|
|
364
|
+
Process.kill signal, pid
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# }}}
|
369
|
+
# ???: maintain_worker_count, all_known_queues {{{
|
370
|
+
|
371
|
+
def maintain_worker_count
|
372
|
+
all_known_queues.each do |queues|
|
373
|
+
delta = worker_delta_for(queues)
|
374
|
+
spawn_missing_workers_for(queues) if delta > 0
|
375
|
+
quit_excess_workers_for(queues) if delta < 0
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def all_known_queues
|
380
|
+
config.keys | workers.keys
|
381
|
+
end
|
382
|
+
|
383
|
+
# }}}
|
384
|
+
# methods that operate on a single grouping of queues {{{
|
385
|
+
# perhaps this means a class is waiting to be extracted
|
386
|
+
|
387
|
+
def spawn_missing_workers_for(queues)
|
388
|
+
worker_delta_for(queues).times do |nr|
|
389
|
+
spawn_worker!(queues)
|
390
|
+
sleep Resque::Pool.spawn_delay if Resque::Pool.spawn_delay
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
def quit_excess_workers_for(queues)
|
395
|
+
delta = -worker_delta_for(queues)
|
396
|
+
pids_for(queues)[0...delta].each do |pid|
|
397
|
+
Process.kill("QUIT", pid)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def worker_delta_for(queues)
|
402
|
+
config.fetch(queues, 0) - workers.fetch(queues, []).size
|
403
|
+
end
|
404
|
+
|
405
|
+
def pids_for(queues)
|
406
|
+
workers[queues].keys
|
407
|
+
end
|
408
|
+
|
409
|
+
def spawn_worker!(queues)
|
410
|
+
worker = create_worker(queues)
|
411
|
+
pid = fork do
|
412
|
+
Process.setpgrp unless Resque::Pool.single_process_group
|
413
|
+
worker.worker_parent_pid = Process.pid
|
414
|
+
log_worker "Starting worker #{worker}"
|
415
|
+
call_after_prefork!(worker)
|
416
|
+
reset_sig_handlers!
|
417
|
+
#self_pipe.each {|io| io.close }
|
418
|
+
worker.work(ENV['INTERVAL'] || DEFAULT_WORKER_INTERVAL) # interval, will block
|
419
|
+
end
|
420
|
+
workers[queues][pid] = worker
|
421
|
+
call_after_spawn!(worker, pid, workers)
|
422
|
+
end
|
423
|
+
|
424
|
+
def create_worker(queues)
|
425
|
+
queues = queues.to_s.split(',')
|
426
|
+
worker = ::Resque::Worker.new(*queues)
|
427
|
+
worker.pool_master_pid = Process.pid
|
428
|
+
worker.term_timeout = (ENV['RESQUE_TERM_TIMEOUT'] || 4.0).to_f
|
429
|
+
worker.term_child = ENV['TERM_CHILD']
|
430
|
+
if worker.respond_to?(:run_at_exit_hooks=)
|
431
|
+
# resque doesn't support this until 1.24, but we support 1.22
|
432
|
+
worker.run_at_exit_hooks = ENV['RUN_AT_EXIT_HOOKS'] || false
|
433
|
+
end
|
434
|
+
if ENV['LOGGING'] || ENV['VERBOSE']
|
435
|
+
worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
|
436
|
+
end
|
437
|
+
if ENV['VVERBOSE']
|
438
|
+
worker.very_verbose = ENV['VVERBOSE']
|
439
|
+
end
|
440
|
+
worker
|
441
|
+
end
|
442
|
+
|
443
|
+
# }}}
|
444
|
+
|
445
|
+
end
|
446
|
+
end
|