vitobotta-resque-pool 0.3.0.dev
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.
- data/Changelog.md +49 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +20 -0
- data/README.md +153 -0
- data/Rakefile +17 -0
- data/bin/resque-pool +5 -0
- data/config/alternate.yml +4 -0
- data/config/cucumber.yml +3 -0
- data/examples/Gemfile +1 -0
- data/examples/Gemfile.lock +67 -0
- data/examples/Rakefile +8 -0
- data/examples/chef_cookbook/recipes/default.rb +46 -0
- data/examples/chef_cookbook/templates/default/initd.erb +69 -0
- data/examples/chef_cookbook/templates/default/monitrc.erb +6 -0
- data/examples/rails-resque.rake +22 -0
- data/examples/resque-pool.yml +4 -0
- data/features/basic_daemon_config.feature +68 -0
- data/features/step_definitions/daemon_steps.rb +29 -0
- data/features/step_definitions/resque-pool_steps.rb +147 -0
- data/features/support/aruba_daemon_support.rb +60 -0
- data/features/support/env.rb +1 -0
- data/lib/resque/pool/cli.rb +116 -0
- data/lib/resque/pool/logging.rb +58 -0
- data/lib/resque/pool/pooled_worker.rb +21 -0
- data/lib/resque/pool/tasks.rb +20 -0
- data/lib/resque/pool/version.rb +5 -0
- data/lib/resque/pool.rb +331 -0
- data/resque-pool.gemspec +34 -0
- data/spec/mock_config.rb +6 -0
- data/spec/resque-pool.yml +13 -0
- data/spec/resque_pool_spec.rb +134 -0
- data/spec/spec_helper.rb +3 -0
- data/tmp/aruba/Rakefile +1 -0
- metadata +175 -0
data/lib/resque/pool.rb
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require 'resque'
|
|
3
|
+
require 'resque/pool/version'
|
|
4
|
+
require 'resque/pool/logging'
|
|
5
|
+
require 'resque/pool/pooled_worker'
|
|
6
|
+
require 'fcntl'
|
|
7
|
+
require 'yaml'
|
|
8
|
+
|
|
9
|
+
module Resque
|
|
10
|
+
class Pool
|
|
11
|
+
SIG_QUEUE_MAX_SIZE = 5
|
|
12
|
+
DEFAULT_WORKER_INTERVAL = 5
|
|
13
|
+
QUEUE_SIGS = [ :QUIT, :INT, :TERM, :USR1, :USR2, :CONT, :HUP, :WINCH, ]
|
|
14
|
+
CHUNK_SIZE = (16 * 1024)
|
|
15
|
+
|
|
16
|
+
include Logging
|
|
17
|
+
attr_reader :config
|
|
18
|
+
attr_reader :workers
|
|
19
|
+
|
|
20
|
+
def initialize(config)
|
|
21
|
+
init_config(config)
|
|
22
|
+
@workers = {}
|
|
23
|
+
procline "(initialized)"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Config: after_prefork {{{
|
|
27
|
+
|
|
28
|
+
# The `after_prefork` hook will be run in workers if you are using the
|
|
29
|
+
# preforking master worker to save memory. Use this hook to reload
|
|
30
|
+
# database connections and so forth to ensure that they're not shared
|
|
31
|
+
# among workers.
|
|
32
|
+
#
|
|
33
|
+
# Call with a block to set the hook.
|
|
34
|
+
# Call with no arguments to return the hook.
|
|
35
|
+
def self.after_prefork(&block)
|
|
36
|
+
block ? (@after_prefork = block) : @after_prefork
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Set the after_prefork proc.
|
|
40
|
+
def self.after_prefork=(after_prefork)
|
|
41
|
+
@after_prefork = after_prefork
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def call_after_prefork!
|
|
45
|
+
self.class.after_prefork && self.class.after_prefork.call
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# }}}
|
|
49
|
+
# Config: class methods to start up the pool using the default config {{{
|
|
50
|
+
|
|
51
|
+
@config_files = ["resque-pool.yml", "config/resque-pool.yml"]
|
|
52
|
+
class << self; attr_accessor :config_files; end
|
|
53
|
+
def self.choose_config_file
|
|
54
|
+
if ENV["RESQUE_POOL_CONFIG"]
|
|
55
|
+
ENV["RESQUE_POOL_CONFIG"]
|
|
56
|
+
else
|
|
57
|
+
@config_files.detect { |f| File.exist?(f) }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.run
|
|
62
|
+
if GC.respond_to?(:copy_on_write_friendly=)
|
|
63
|
+
GC.copy_on_write_friendly = true
|
|
64
|
+
end
|
|
65
|
+
Resque::Pool.new(choose_config_file).start.join
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# }}}
|
|
69
|
+
# Config: load config and config file {{{
|
|
70
|
+
|
|
71
|
+
def config_file
|
|
72
|
+
@config_file || (!@config && ::Resque::Pool.choose_config_file)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def init_config(config)
|
|
76
|
+
case config
|
|
77
|
+
when String, nil
|
|
78
|
+
@config_file = config
|
|
79
|
+
else
|
|
80
|
+
@config = config.dup
|
|
81
|
+
end
|
|
82
|
+
load_config
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def load_config
|
|
86
|
+
if config_file
|
|
87
|
+
@config = YAML.load_file(config_file)
|
|
88
|
+
else
|
|
89
|
+
@config ||= {}
|
|
90
|
+
end
|
|
91
|
+
environment and @config[environment] and config.merge!(@config[environment])
|
|
92
|
+
config.delete_if {|key, value| value.is_a? Hash }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def environment
|
|
96
|
+
if defined? RAILS_ENV
|
|
97
|
+
RAILS_ENV
|
|
98
|
+
else
|
|
99
|
+
ENV['RACK_ENV'] || ENV['RAILS_ENV'] || ENV['RESQUE_ENV']
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# }}}
|
|
104
|
+
|
|
105
|
+
# Sig handlers and self pipe management {{{
|
|
106
|
+
|
|
107
|
+
def self_pipe; @self_pipe ||= [] end
|
|
108
|
+
def sig_queue; @sig_queue ||= [] end
|
|
109
|
+
|
|
110
|
+
def init_self_pipe!
|
|
111
|
+
self_pipe.each { |io| io.close rescue nil }
|
|
112
|
+
self_pipe.replace(IO.pipe)
|
|
113
|
+
self_pipe.each { |io| io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def init_sig_handlers!
|
|
117
|
+
QUEUE_SIGS.each { |sig| trap_deferred(sig) }
|
|
118
|
+
trap(:CHLD) { |_| awaken_master }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def awaken_master
|
|
122
|
+
begin
|
|
123
|
+
self_pipe.last.write_nonblock('.') # wakeup master process from select
|
|
124
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
|
125
|
+
# pipe is full, master should wake up anyways
|
|
126
|
+
retry
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class QuitNowException < Exception; end
|
|
131
|
+
# defer a signal for later processing in #join (master process)
|
|
132
|
+
def trap_deferred(signal)
|
|
133
|
+
trap(signal) do |sig_nr|
|
|
134
|
+
if @waiting_for_reaper && [:INT, :TERM].include?(signal)
|
|
135
|
+
log "Recieved #{signal}: short circuiting QUIT waitpid"
|
|
136
|
+
raise QuitNowException
|
|
137
|
+
end
|
|
138
|
+
if sig_queue.size < SIG_QUEUE_MAX_SIZE
|
|
139
|
+
sig_queue << signal
|
|
140
|
+
awaken_master
|
|
141
|
+
else
|
|
142
|
+
log "ignoring SIG#{signal}, queue=#{sig_queue.inspect}"
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def reset_sig_handlers!
|
|
148
|
+
QUEUE_SIGS.each {|sig| trap(sig, "DEFAULT") }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def handle_sig_queue!
|
|
152
|
+
case signal = sig_queue.shift
|
|
153
|
+
when :USR1, :USR2, :CONT
|
|
154
|
+
log "#{signal}: sending to all workers"
|
|
155
|
+
signal_all_workers(signal)
|
|
156
|
+
when :HUP
|
|
157
|
+
log "HUP: reload config file and reload logfiles"
|
|
158
|
+
load_config
|
|
159
|
+
Logging.reopen_logs!
|
|
160
|
+
log "HUP: gracefully shutdown old children (which have old logfiles open)"
|
|
161
|
+
signal_all_workers(:QUIT)
|
|
162
|
+
log "HUP: new children will inherit new logfiles"
|
|
163
|
+
maintain_worker_count
|
|
164
|
+
when :WINCH
|
|
165
|
+
log "WINCH: gracefully stopping all workers"
|
|
166
|
+
@config = {}
|
|
167
|
+
maintain_worker_count
|
|
168
|
+
when :QUIT
|
|
169
|
+
log "QUIT: graceful shutdown, waiting for children"
|
|
170
|
+
signal_all_workers(:QUIT)
|
|
171
|
+
reap_all_workers(0) # will hang until all workers are shutdown
|
|
172
|
+
:break
|
|
173
|
+
when :INT
|
|
174
|
+
log "INT: immediate shutdown (graceful worker shutdown)"
|
|
175
|
+
signal_all_workers(:QUIT)
|
|
176
|
+
:break
|
|
177
|
+
when :TERM
|
|
178
|
+
log "TERM: immediate shutdown (and immediate worker shutdown)"
|
|
179
|
+
signal_all_workers(:TERM)
|
|
180
|
+
:break
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# }}}
|
|
185
|
+
# start, join, and master sleep {{{
|
|
186
|
+
|
|
187
|
+
def start
|
|
188
|
+
procline("(starting)")
|
|
189
|
+
init_self_pipe!
|
|
190
|
+
init_sig_handlers!
|
|
191
|
+
maintain_worker_count
|
|
192
|
+
procline("(started)")
|
|
193
|
+
log "started manager"
|
|
194
|
+
report_worker_pool_pids
|
|
195
|
+
self
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def report_worker_pool_pids
|
|
199
|
+
if workers.empty?
|
|
200
|
+
log "Pool is empty"
|
|
201
|
+
else
|
|
202
|
+
log "Pool contains worker PIDs: #{all_pids.inspect}"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def join
|
|
207
|
+
loop do
|
|
208
|
+
reap_all_workers
|
|
209
|
+
break if handle_sig_queue! == :break
|
|
210
|
+
if sig_queue.empty?
|
|
211
|
+
master_sleep
|
|
212
|
+
maintain_worker_count
|
|
213
|
+
end
|
|
214
|
+
procline("managing #{all_pids.inspect}")
|
|
215
|
+
end
|
|
216
|
+
procline("(shutting down)")
|
|
217
|
+
#stop # gracefully shutdown all workers on our way out
|
|
218
|
+
log "manager finished"
|
|
219
|
+
#unlink_pid_safe(pid) if pid
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def master_sleep
|
|
223
|
+
begin
|
|
224
|
+
ready = IO.select([self_pipe.first], nil, nil, 1) or return
|
|
225
|
+
ready.first && ready.first.first or return
|
|
226
|
+
loop { self_pipe.first.read_nonblock(CHUNK_SIZE) }
|
|
227
|
+
rescue Errno::EAGAIN, Errno::EINTR
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# }}}
|
|
232
|
+
# worker process management {{{
|
|
233
|
+
|
|
234
|
+
def reap_all_workers(waitpid_flags=Process::WNOHANG)
|
|
235
|
+
@waiting_for_reaper = waitpid_flags == 0
|
|
236
|
+
begin
|
|
237
|
+
loop do
|
|
238
|
+
# -1, wait for any child process
|
|
239
|
+
wpid, status = Process.waitpid2(-1, waitpid_flags)
|
|
240
|
+
wpid or break
|
|
241
|
+
worker = delete_worker(wpid)
|
|
242
|
+
# TODO: close any file descriptors connected to worker, if any
|
|
243
|
+
log "Reaped resque worker[#{status.pid}] (status: #{status.exitstatus}) queues: #{worker.queues.join(",")}"
|
|
244
|
+
end
|
|
245
|
+
rescue Errno::ECHILD, QuitNowException
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def delete_worker(pid)
|
|
250
|
+
worker = nil
|
|
251
|
+
workers.detect do |queues, pid_to_worker|
|
|
252
|
+
worker = pid_to_worker.delete(pid)
|
|
253
|
+
end
|
|
254
|
+
worker
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def all_pids
|
|
258
|
+
workers.map {|q,workers| workers.keys }.flatten
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def signal_all_workers(signal)
|
|
262
|
+
all_pids.each do |pid|
|
|
263
|
+
Process.kill signal, pid
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# }}}
|
|
268
|
+
# ???: maintain_worker_count, all_known_queues {{{
|
|
269
|
+
|
|
270
|
+
def maintain_worker_count
|
|
271
|
+
all_known_queues.each do |queues|
|
|
272
|
+
delta = worker_delta_for(queues)
|
|
273
|
+
spawn_missing_workers_for(queues) if delta > 0
|
|
274
|
+
quit_excess_workers_for(queues) if delta < 0
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def all_known_queues
|
|
279
|
+
config.keys | workers.keys
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# }}}
|
|
283
|
+
# methods that operate on a single grouping of queues {{{
|
|
284
|
+
# perhaps this means a class is waiting to be extracted
|
|
285
|
+
|
|
286
|
+
def spawn_missing_workers_for(queues)
|
|
287
|
+
worker_delta_for(queues).times do |nr|
|
|
288
|
+
spawn_worker!(queues)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def quit_excess_workers_for(queues)
|
|
293
|
+
delta = -worker_delta_for(queues)
|
|
294
|
+
pids_for(queues)[0...delta].each do |pid|
|
|
295
|
+
Process.kill("QUIT", pid)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def worker_delta_for(queues)
|
|
300
|
+
config.fetch(queues, 0) - workers.fetch(queues, []).size
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def pids_for(queues)
|
|
304
|
+
workers[queues].keys
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def spawn_worker!(queues)
|
|
308
|
+
worker = create_worker(queues)
|
|
309
|
+
pid = fork do
|
|
310
|
+
log_worker "Starting worker #{worker}"
|
|
311
|
+
call_after_prefork!
|
|
312
|
+
reset_sig_handlers!
|
|
313
|
+
#self_pipe.each {|io| io.close }
|
|
314
|
+
worker.work(ENV['INTERVAL'] || DEFAULT_WORKER_INTERVAL) # interval, will block
|
|
315
|
+
end
|
|
316
|
+
workers[queues] ||= {}
|
|
317
|
+
workers[queues][pid] = worker
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def create_worker(queues)
|
|
321
|
+
queues = queues.to_s.split(',')
|
|
322
|
+
worker = PooledWorker.new(*queues)
|
|
323
|
+
worker.verbose = ENV['LOGGING'] || ENV['VERBOSE']
|
|
324
|
+
worker.very_verbose = ENV['VVERBOSE']
|
|
325
|
+
worker
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
# }}}
|
|
329
|
+
|
|
330
|
+
end
|
|
331
|
+
end
|
data/resque-pool.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "resque/pool/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "vitobotta-resque-pool"
|
|
7
|
+
s.version = Resque::Pool::VERSION
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.authors = ["nicholas a. evans", "Vito Botta"]
|
|
10
|
+
s.email = ["nick@ekenosen.net", "vito@botta.name"]
|
|
11
|
+
s.homepage = "https://github.com/vitobotta/resque-pool"
|
|
12
|
+
s.summary = "quickly and easily fork a pool of resque workers"
|
|
13
|
+
s.description = <<-EOF
|
|
14
|
+
quickly and easily fork a pool of resque workers,
|
|
15
|
+
saving memory (w/REE) and monitoring their uptime
|
|
16
|
+
EOF
|
|
17
|
+
|
|
18
|
+
s.add_dependency "resque", "~> 1.13"
|
|
19
|
+
s.add_dependency "trollop", "~> 1.16"
|
|
20
|
+
s.add_dependency "rake"
|
|
21
|
+
s.add_development_dependency "rspec", "~> 2.3.0"
|
|
22
|
+
s.add_development_dependency "cucumber", "~> 0.10.0"
|
|
23
|
+
s.add_development_dependency "aruba", "~> 0.3.2"
|
|
24
|
+
s.add_development_dependency "SystemTimer" unless RUBY_VERSION =~ /1\.9/ # to silence redis gem's warning
|
|
25
|
+
s.add_development_dependency "bundler", "~> 1.0"
|
|
26
|
+
|
|
27
|
+
# hidden files are automatically ignored by Dir.glob
|
|
28
|
+
ignore_patterns = %w[**/*.gem **/*.pid **/*.log pkg Gemfile.lock]
|
|
29
|
+
ignore_files = ignore_patterns.inject([]) {|a,p| a + Dir[p] }
|
|
30
|
+
s.files = Dir["**/*"] - ignore_files
|
|
31
|
+
s.test_files = Dir.glob("{spec,features}/**/*.{rb,yml,feature}")
|
|
32
|
+
s.executables = 'resque-pool'
|
|
33
|
+
s.require_paths = ["lib"]
|
|
34
|
+
end
|
data/spec/mock_config.rb
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.configure do |config|
|
|
4
|
+
config.after {
|
|
5
|
+
Object.send(:remove_const, :RAILS_ENV) if defined? RAILS_ENV
|
|
6
|
+
ENV.delete 'RACK_ENV'
|
|
7
|
+
ENV.delete 'RAILS_ENV'
|
|
8
|
+
ENV.delete 'RESQUE_ENV'
|
|
9
|
+
}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe Resque::Pool, "when loading a simple pool configuration" do
|
|
13
|
+
let(:config) do
|
|
14
|
+
{ 'foo' => 1, 'bar' => 2, 'foo,bar' => 3, 'bar,foo' => 4, }
|
|
15
|
+
end
|
|
16
|
+
subject { Resque::Pool.new(config) }
|
|
17
|
+
|
|
18
|
+
context "when ENV['RACK_ENV'] is set" do
|
|
19
|
+
before { ENV['RACK_ENV'] = 'development' }
|
|
20
|
+
|
|
21
|
+
it "should load the values from the Hash" do
|
|
22
|
+
subject.config["foo"].should == 1
|
|
23
|
+
subject.config["bar"].should == 2
|
|
24
|
+
subject.config["foo,bar"].should == 3
|
|
25
|
+
subject.config["bar,foo"].should == 4
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe Resque::Pool, "when loading the pool configuration from a Hash" do
|
|
32
|
+
|
|
33
|
+
let(:config) do
|
|
34
|
+
{
|
|
35
|
+
'foo' => 8,
|
|
36
|
+
'test' => { 'bar' => 10, 'foo,bar' => 12 },
|
|
37
|
+
'development' => { 'baz' => 14, 'foo,bar' => 16 },
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
subject { Resque::Pool.new(config) }
|
|
42
|
+
|
|
43
|
+
context "when RAILS_ENV is set" do
|
|
44
|
+
before { RAILS_ENV = "test" }
|
|
45
|
+
|
|
46
|
+
it "should load the default values from the Hash" do
|
|
47
|
+
subject.config["foo"].should == 8
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should merge the values for the correct RAILS_ENV" do
|
|
51
|
+
subject.config["bar"].should == 10
|
|
52
|
+
subject.config["foo,bar"].should == 12
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should not load the values for the other environments" do
|
|
56
|
+
subject.config["foo,bar"].should == 12
|
|
57
|
+
subject.config["baz"].should be_nil
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "when ENV['RESQUE_ENV'] is set" do
|
|
63
|
+
before { ENV['RESQUE_ENV'] = 'development' }
|
|
64
|
+
it "should load the config for that environment" do
|
|
65
|
+
subject.config["foo"].should == 8
|
|
66
|
+
subject.config["foo,bar"].should == 16
|
|
67
|
+
subject.config["baz"].should == 14
|
|
68
|
+
subject.config["bar"].should be_nil
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "when there is no environment" do
|
|
73
|
+
it "should load the default values only" do
|
|
74
|
+
subject.config["foo"].should == 8
|
|
75
|
+
subject.config["bar"].should be_nil
|
|
76
|
+
subject.config["foo,bar"].should be_nil
|
|
77
|
+
subject.config["baz"].should be_nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe Resque::Pool, "given no configuration" do
|
|
84
|
+
subject { Resque::Pool.new(nil) }
|
|
85
|
+
it "should have no worker types" do
|
|
86
|
+
subject.config.should == {}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe Resque::Pool, "when loading the pool configuration from a file" do
|
|
91
|
+
|
|
92
|
+
subject { Resque::Pool.new("spec/resque-pool.yml") }
|
|
93
|
+
|
|
94
|
+
context "when RAILS_ENV is set" do
|
|
95
|
+
before { RAILS_ENV = "test" }
|
|
96
|
+
|
|
97
|
+
it "should load the default YAML" do
|
|
98
|
+
subject.config["foo"].should == 1
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should merge the YAML for the correct RAILS_ENV" do
|
|
102
|
+
subject.config["bar"].should == 5
|
|
103
|
+
subject.config["foo,bar"].should == 3
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "should not load the YAML for the other environments" do
|
|
107
|
+
subject.config["foo"].should == 1
|
|
108
|
+
subject.config["bar"].should == 5
|
|
109
|
+
subject.config["foo,bar"].should == 3
|
|
110
|
+
subject.config["baz"].should be_nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
context "when ENV['RACK_ENV'] is set" do
|
|
116
|
+
before { ENV['RACK_ENV'] = 'development' }
|
|
117
|
+
it "should load the config for that environment" do
|
|
118
|
+
subject.config["foo"].should == 1
|
|
119
|
+
subject.config["foo,bar"].should == 4
|
|
120
|
+
subject.config["baz"].should == 23
|
|
121
|
+
subject.config["bar"].should be_nil
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context "when there is no environment" do
|
|
126
|
+
it "should load the default values only" do
|
|
127
|
+
subject.config["foo"].should == 1
|
|
128
|
+
subject.config["bar"].should be_nil
|
|
129
|
+
subject.config["foo,bar"].should be_nil
|
|
130
|
+
subject.config["baz"].should be_nil
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/tmp/aruba/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'resque/pool/tasks'
|
metadata
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: vitobotta-resque-pool
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease: 6
|
|
5
|
+
version: 0.3.0.dev
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- nicholas a. evans
|
|
9
|
+
- Vito Botta
|
|
10
|
+
autorequire:
|
|
11
|
+
bindir: bin
|
|
12
|
+
cert_chain: []
|
|
13
|
+
|
|
14
|
+
date: 2011-07-08 00:00:00 +01:00
|
|
15
|
+
default_executable:
|
|
16
|
+
dependencies:
|
|
17
|
+
- !ruby/object:Gem::Dependency
|
|
18
|
+
name: resque
|
|
19
|
+
prerelease: false
|
|
20
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
21
|
+
none: false
|
|
22
|
+
requirements:
|
|
23
|
+
- - ~>
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: "1.13"
|
|
26
|
+
type: :runtime
|
|
27
|
+
version_requirements: *id001
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: trollop
|
|
30
|
+
prerelease: false
|
|
31
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
32
|
+
none: false
|
|
33
|
+
requirements:
|
|
34
|
+
- - ~>
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: "1.16"
|
|
37
|
+
type: :runtime
|
|
38
|
+
version_requirements: *id002
|
|
39
|
+
- !ruby/object:Gem::Dependency
|
|
40
|
+
name: rake
|
|
41
|
+
prerelease: false
|
|
42
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
43
|
+
none: false
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: "0"
|
|
48
|
+
type: :runtime
|
|
49
|
+
version_requirements: *id003
|
|
50
|
+
- !ruby/object:Gem::Dependency
|
|
51
|
+
name: rspec
|
|
52
|
+
prerelease: false
|
|
53
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
54
|
+
none: false
|
|
55
|
+
requirements:
|
|
56
|
+
- - ~>
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: 2.3.0
|
|
59
|
+
type: :development
|
|
60
|
+
version_requirements: *id004
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: cucumber
|
|
63
|
+
prerelease: false
|
|
64
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ~>
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: 0.10.0
|
|
70
|
+
type: :development
|
|
71
|
+
version_requirements: *id005
|
|
72
|
+
- !ruby/object:Gem::Dependency
|
|
73
|
+
name: aruba
|
|
74
|
+
prerelease: false
|
|
75
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
|
76
|
+
none: false
|
|
77
|
+
requirements:
|
|
78
|
+
- - ~>
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: 0.3.2
|
|
81
|
+
type: :development
|
|
82
|
+
version_requirements: *id006
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: bundler
|
|
85
|
+
prerelease: false
|
|
86
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
|
87
|
+
none: false
|
|
88
|
+
requirements:
|
|
89
|
+
- - ~>
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: "1.0"
|
|
92
|
+
type: :development
|
|
93
|
+
version_requirements: *id007
|
|
94
|
+
description: " quickly and easily fork a pool of resque workers,\n saving memory (w/REE) and monitoring their uptime\n"
|
|
95
|
+
email:
|
|
96
|
+
- nick@ekenosen.net
|
|
97
|
+
- vito@botta.name
|
|
98
|
+
executables:
|
|
99
|
+
- resque-pool
|
|
100
|
+
extensions: []
|
|
101
|
+
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
|
|
104
|
+
files:
|
|
105
|
+
- bin/resque-pool
|
|
106
|
+
- Changelog.md
|
|
107
|
+
- config/alternate.yml
|
|
108
|
+
- config/cucumber.yml
|
|
109
|
+
- examples/chef_cookbook/recipes/default.rb
|
|
110
|
+
- examples/chef_cookbook/templates/default/initd.erb
|
|
111
|
+
- examples/chef_cookbook/templates/default/monitrc.erb
|
|
112
|
+
- examples/Gemfile
|
|
113
|
+
- examples/Gemfile.lock
|
|
114
|
+
- examples/rails-resque.rake
|
|
115
|
+
- examples/Rakefile
|
|
116
|
+
- examples/resque-pool.yml
|
|
117
|
+
- features/basic_daemon_config.feature
|
|
118
|
+
- features/step_definitions/daemon_steps.rb
|
|
119
|
+
- features/step_definitions/resque-pool_steps.rb
|
|
120
|
+
- features/support/aruba_daemon_support.rb
|
|
121
|
+
- features/support/env.rb
|
|
122
|
+
- Gemfile
|
|
123
|
+
- lib/resque/pool/cli.rb
|
|
124
|
+
- lib/resque/pool/logging.rb
|
|
125
|
+
- lib/resque/pool/pooled_worker.rb
|
|
126
|
+
- lib/resque/pool/tasks.rb
|
|
127
|
+
- lib/resque/pool/version.rb
|
|
128
|
+
- lib/resque/pool.rb
|
|
129
|
+
- LICENSE.txt
|
|
130
|
+
- Rakefile
|
|
131
|
+
- README.md
|
|
132
|
+
- resque-pool.gemspec
|
|
133
|
+
- spec/mock_config.rb
|
|
134
|
+
- spec/resque-pool.yml
|
|
135
|
+
- spec/resque_pool_spec.rb
|
|
136
|
+
- spec/spec_helper.rb
|
|
137
|
+
- tmp/aruba/Rakefile
|
|
138
|
+
has_rdoc: true
|
|
139
|
+
homepage: https://github.com/vitobotta/resque-pool
|
|
140
|
+
licenses: []
|
|
141
|
+
|
|
142
|
+
post_install_message:
|
|
143
|
+
rdoc_options: []
|
|
144
|
+
|
|
145
|
+
require_paths:
|
|
146
|
+
- lib
|
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
|
+
none: false
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: "0"
|
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
|
+
none: false
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">"
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: 1.3.1
|
|
159
|
+
requirements: []
|
|
160
|
+
|
|
161
|
+
rubyforge_project:
|
|
162
|
+
rubygems_version: 1.6.2
|
|
163
|
+
signing_key:
|
|
164
|
+
specification_version: 3
|
|
165
|
+
summary: quickly and easily fork a pool of resque workers
|
|
166
|
+
test_files:
|
|
167
|
+
- spec/mock_config.rb
|
|
168
|
+
- spec/resque_pool_spec.rb
|
|
169
|
+
- spec/spec_helper.rb
|
|
170
|
+
- spec/resque-pool.yml
|
|
171
|
+
- features/step_definitions/daemon_steps.rb
|
|
172
|
+
- features/step_definitions/resque-pool_steps.rb
|
|
173
|
+
- features/support/aruba_daemon_support.rb
|
|
174
|
+
- features/support/env.rb
|
|
175
|
+
- features/basic_daemon_config.feature
|