rack-rabbit 0.5.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/.gitignore +3 -0
- data/EXAMPLES.md +212 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +42 -0
- data/LICENSE +21 -0
- data/README.md +412 -0
- data/Rakefile +5 -0
- data/bin/rack-rabbit +96 -0
- data/bin/rr +99 -0
- data/lib/rack-rabbit.rb +63 -0
- data/lib/rack-rabbit/adapter.rb +85 -0
- data/lib/rack-rabbit/adapter/amqp.rb +114 -0
- data/lib/rack-rabbit/adapter/bunny.rb +87 -0
- data/lib/rack-rabbit/adapter/mock.rb +92 -0
- data/lib/rack-rabbit/client.rb +181 -0
- data/lib/rack-rabbit/config.rb +260 -0
- data/lib/rack-rabbit/handler.rb +44 -0
- data/lib/rack-rabbit/message.rb +95 -0
- data/lib/rack-rabbit/middleware/program_name.rb +34 -0
- data/lib/rack-rabbit/response.rb +43 -0
- data/lib/rack-rabbit/server.rb +263 -0
- data/lib/rack-rabbit/signals.rb +62 -0
- data/lib/rack-rabbit/subscriber.rb +77 -0
- data/lib/rack-rabbit/worker.rb +84 -0
- data/rack-rabbit.gemspec +26 -0
- data/test/apps/config.ru +7 -0
- data/test/apps/custom.conf +27 -0
- data/test/apps/custom.ru +7 -0
- data/test/apps/empty.conf +1 -0
- data/test/apps/error.ru +7 -0
- data/test/apps/mirror.ru +19 -0
- data/test/apps/sinatra.ru +37 -0
- data/test/apps/sleep.ru +21 -0
- data/test/test_case.rb +154 -0
- data/test/unit/middleware/test_program_name.rb +32 -0
- data/test/unit/test_client.rb +275 -0
- data/test/unit/test_config.rb +403 -0
- data/test/unit/test_handler.rb +92 -0
- data/test/unit/test_message.rb +213 -0
- data/test/unit/test_response.rb +59 -0
- data/test/unit/test_signals.rb +45 -0
- data/test/unit/test_subscriber.rb +140 -0
- metadata +91 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
begin
|
2
|
+
require 'bunny'
|
3
|
+
rescue LoadError
|
4
|
+
abort "missing 'bunny' gem"
|
5
|
+
end
|
6
|
+
|
7
|
+
module RackRabbit
|
8
|
+
class Adapter
|
9
|
+
class Bunny < RackRabbit::Adapter
|
10
|
+
|
11
|
+
attr_accessor :connection, :channel
|
12
|
+
|
13
|
+
def connect
|
14
|
+
return if connected?
|
15
|
+
@connection = ::Bunny.new(connection_options)
|
16
|
+
connection.start
|
17
|
+
@channel = connection.create_channel
|
18
|
+
channel.prefetch(1)
|
19
|
+
end
|
20
|
+
|
21
|
+
def disconnect
|
22
|
+
channel.close unless channel.nil?
|
23
|
+
connection.close unless connection.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def connected?
|
27
|
+
!@connection.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def subscribe(options = {}, &block)
|
31
|
+
queue = get_queue(options.delete(:queue)) || channel.queue("", :exclusive => true)
|
32
|
+
exchange = get_exchange(options.delete(:exchange), options.delete(:exchange_type))
|
33
|
+
if exchange
|
34
|
+
queue.bind(exchange, :routing_key => options.delete(:routing_key))
|
35
|
+
end
|
36
|
+
queue.subscribe(options) do |delivery_info, properties, payload|
|
37
|
+
yield Message.new(delivery_info.delivery_tag, properties, payload, self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def publish(payload, properties)
|
42
|
+
exchange = get_exchange(properties.delete(:exchange), properties.delete(:exchange_type))
|
43
|
+
exchange ||= channel.default_exchange
|
44
|
+
exchange.publish(payload || "", properties)
|
45
|
+
end
|
46
|
+
|
47
|
+
def with_reply_queue(&block)
|
48
|
+
yield channel.queue("", :exclusive => true, :auto_delete => true)
|
49
|
+
end
|
50
|
+
|
51
|
+
def ack(delivery_tag)
|
52
|
+
channel.acknowledge(delivery_tag, false)
|
53
|
+
end
|
54
|
+
|
55
|
+
def reject(delivery_tag)
|
56
|
+
channel.reject(delivery_tag, false)
|
57
|
+
end
|
58
|
+
|
59
|
+
#========================================================================
|
60
|
+
# PRIVATE IMPLEMENTATION
|
61
|
+
#========================================================================
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def get_exchange(ex = :default, type = :direct)
|
66
|
+
case ex
|
67
|
+
when ::Bunny::Exchange then ex
|
68
|
+
when Symbol, String then channel.send(type || :direct, ex) unless ex.to_s.downcase.to_sym == :default
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_queue(q)
|
75
|
+
case q
|
76
|
+
when ::Bunny::Queue then q
|
77
|
+
when Symbol, String then channel.queue(q)
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#------------------------------------------------------------------------
|
84
|
+
|
85
|
+
end # class Bunny
|
86
|
+
end # module Adapter
|
87
|
+
end # module RackRabbit
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module RackRabbit
|
2
|
+
class Adapter
|
3
|
+
class Mock < RackRabbit::Adapter
|
4
|
+
|
5
|
+
attr_accessor :connection
|
6
|
+
|
7
|
+
def startup
|
8
|
+
@started = true
|
9
|
+
end
|
10
|
+
|
11
|
+
def shutdown
|
12
|
+
@started = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def started?
|
16
|
+
!!@started
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect
|
20
|
+
@connected = true
|
21
|
+
end
|
22
|
+
|
23
|
+
def disconnect
|
24
|
+
@connected = false
|
25
|
+
end
|
26
|
+
|
27
|
+
def connected?
|
28
|
+
!!@connected
|
29
|
+
end
|
30
|
+
|
31
|
+
def subscribe(options = {}, &block)
|
32
|
+
@subscribe_options = options
|
33
|
+
while !queue.empty?
|
34
|
+
message = queue.shift
|
35
|
+
yield message
|
36
|
+
subscribed_messages << message
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def publish(body, properties)
|
41
|
+
published_messages << properties.merge(:body => body)
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_reply_queue(&block)
|
45
|
+
yield OpenStruct.new :name => "reply.queue"
|
46
|
+
end
|
47
|
+
|
48
|
+
def ack(delivery_tag)
|
49
|
+
acked_messages << delivery_tag
|
50
|
+
end
|
51
|
+
|
52
|
+
def reject(delivery_tag)
|
53
|
+
rejected_messages << delivery_tag
|
54
|
+
end
|
55
|
+
|
56
|
+
#========================================================================
|
57
|
+
# TEST HELPER METHODS
|
58
|
+
#========================================================================
|
59
|
+
|
60
|
+
def acked_messages
|
61
|
+
@acked_messages ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
def rejected_messages
|
65
|
+
@rejected_messages ||= []
|
66
|
+
end
|
67
|
+
|
68
|
+
def published_messages
|
69
|
+
@published_messages ||= []
|
70
|
+
end
|
71
|
+
|
72
|
+
def subscribed_messages
|
73
|
+
@subscribed_messages ||= []
|
74
|
+
end
|
75
|
+
|
76
|
+
def queue
|
77
|
+
@queue ||= []
|
78
|
+
end
|
79
|
+
|
80
|
+
def prime(message)
|
81
|
+
queue << message
|
82
|
+
end
|
83
|
+
|
84
|
+
def subscribe_options
|
85
|
+
@subscribe_options
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
require 'rack-rabbit'
|
4
|
+
require 'rack-rabbit/adapter'
|
5
|
+
require 'rack-rabbit/message'
|
6
|
+
require 'rack-rabbit/response'
|
7
|
+
|
8
|
+
module RackRabbit
|
9
|
+
class Client
|
10
|
+
|
11
|
+
#--------------------------------------------------------------------------
|
12
|
+
|
13
|
+
attr_reader :rabbit
|
14
|
+
|
15
|
+
def initialize(options = nil)
|
16
|
+
@rabbit = Adapter.load(DEFAULT_RABBIT.merge(options || {}))
|
17
|
+
connect
|
18
|
+
end
|
19
|
+
|
20
|
+
#--------------------------------------------------------------------------
|
21
|
+
|
22
|
+
def connect
|
23
|
+
rabbit.connect
|
24
|
+
end
|
25
|
+
|
26
|
+
def disconnect
|
27
|
+
rabbit.disconnect
|
28
|
+
end
|
29
|
+
|
30
|
+
#--------------------------------------------------------------------------
|
31
|
+
|
32
|
+
def get(queue, path, options = {})
|
33
|
+
request(queue, path, "", options.merge(:method => :GET))
|
34
|
+
end
|
35
|
+
|
36
|
+
def post(queue, path, body, options = {})
|
37
|
+
request(queue, path, body, options.merge(:method => :POST))
|
38
|
+
end
|
39
|
+
|
40
|
+
def put(queue, path, body, options = {})
|
41
|
+
request(queue, path, body, options.merge(:method => :PUT))
|
42
|
+
end
|
43
|
+
|
44
|
+
def delete(queue, path, options = {})
|
45
|
+
request(queue, path, "", options.merge(:method => :DELETE))
|
46
|
+
end
|
47
|
+
|
48
|
+
#--------------------------------------------------------------------------
|
49
|
+
|
50
|
+
def request(queue, path, body, options = {})
|
51
|
+
|
52
|
+
id = options[:id] || SecureRandom.uuid # allow dependency injection for test purposes
|
53
|
+
lock = Mutex.new
|
54
|
+
condition = ConditionVariable.new
|
55
|
+
method = options[:method] || :GET
|
56
|
+
headers = options[:headers] || {}
|
57
|
+
response = nil
|
58
|
+
|
59
|
+
rabbit.with_reply_queue do |reply_queue|
|
60
|
+
|
61
|
+
rabbit.subscribe(:queue => reply_queue) do |message|
|
62
|
+
if message.correlation_id == id
|
63
|
+
lock.synchronize do
|
64
|
+
response = Response.new(message.status, message.headers, message.body)
|
65
|
+
condition.signal
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
rabbit.publish(body,
|
71
|
+
:correlation_id => id,
|
72
|
+
:routing_key => queue,
|
73
|
+
:reply_to => reply_queue.name,
|
74
|
+
:priority => options[:priority],
|
75
|
+
:content_type => options[:content_type] || default_content_type,
|
76
|
+
:content_encoding => options[:content_encoding] || default_content_encoding,
|
77
|
+
:timestamp => options[:timestamp] || default_timestamp,
|
78
|
+
:headers => headers.merge({
|
79
|
+
RackRabbit::HEADER::METHOD => method.to_s.upcase,
|
80
|
+
RackRabbit::HEADER::PATH => path
|
81
|
+
})
|
82
|
+
)
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
lock.synchronize do
|
87
|
+
condition.wait(lock) unless response
|
88
|
+
end
|
89
|
+
|
90
|
+
response
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
#--------------------------------------------------------------------------
|
95
|
+
|
96
|
+
def enqueue(queue, path, body, options = {})
|
97
|
+
|
98
|
+
method = options[:method] || :POST
|
99
|
+
headers = options[:headers] || {}
|
100
|
+
|
101
|
+
rabbit.publish(body,
|
102
|
+
:routing_key => queue,
|
103
|
+
:priority => options[:priority],
|
104
|
+
:content_type => options[:content_type] || default_content_type,
|
105
|
+
:content_encoding => options[:content_encoding] || default_content_encoding,
|
106
|
+
:timestamp => options[:timestamp] || default_timestamp,
|
107
|
+
:headers => headers.merge({
|
108
|
+
RackRabbit::HEADER::METHOD => method.to_s.upcase,
|
109
|
+
RackRabbit::HEADER::PATH => path
|
110
|
+
})
|
111
|
+
)
|
112
|
+
|
113
|
+
true
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
#--------------------------------------------------------------------------
|
118
|
+
|
119
|
+
def publish(exchange, path, body, options = {})
|
120
|
+
|
121
|
+
method = options[:method] || :POST
|
122
|
+
headers = options[:headers] || {}
|
123
|
+
|
124
|
+
rabbit.publish(body,
|
125
|
+
:exchange => exchange,
|
126
|
+
:exchange_type => options[:exchange_type] || options[:type] || :fanout,
|
127
|
+
:routing_key => options[:routing_key] || options[:route],
|
128
|
+
:priority => options[:priority],
|
129
|
+
:content_type => options[:content_type] || default_content_type,
|
130
|
+
:content_encoding => options[:content_encoding] || default_content_encoding,
|
131
|
+
:timestamp => options[:timestamp] || default_timestamp,
|
132
|
+
:headers => headers.merge({
|
133
|
+
RackRabbit::HEADER::METHOD => method.to_s.upcase,
|
134
|
+
RackRabbit::HEADER::PATH => path
|
135
|
+
})
|
136
|
+
)
|
137
|
+
|
138
|
+
true
|
139
|
+
|
140
|
+
end
|
141
|
+
#--------------------------------------------------------------------------
|
142
|
+
|
143
|
+
def default_content_type
|
144
|
+
'text/plain'
|
145
|
+
end
|
146
|
+
|
147
|
+
def default_content_encoding
|
148
|
+
'utf-8'
|
149
|
+
end
|
150
|
+
|
151
|
+
def default_timestamp
|
152
|
+
Time.now.to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
#--------------------------------------------------------------------------
|
156
|
+
|
157
|
+
def self.define_class_method_for(method_name)
|
158
|
+
define_singleton_method(method_name) do |*params|
|
159
|
+
options = params.last.is_a?(Hash) ? params.pop : {}
|
160
|
+
client = Client.new(options.delete(:rabbit))
|
161
|
+
response = client.send(method_name, *params, options)
|
162
|
+
client.disconnect
|
163
|
+
response
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
define_class_method_for :get
|
168
|
+
define_class_method_for :post
|
169
|
+
define_class_method_for :put
|
170
|
+
define_class_method_for :delete
|
171
|
+
define_class_method_for :request
|
172
|
+
define_class_method_for :enqueue
|
173
|
+
define_class_method_for :publish
|
174
|
+
|
175
|
+
#--------------------------------------------------------------------------
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
RR = RackRabbit::Client # much less typing for client applications
|
181
|
+
|
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'rack'
|
3
|
+
|
4
|
+
require 'rack-rabbit'
|
5
|
+
|
6
|
+
module RackRabbit
|
7
|
+
class Config
|
8
|
+
|
9
|
+
#--------------------------------------------------------------------------
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
@values = {}
|
13
|
+
options.each{|key, value| send(key, value) if respond_to?(key)}
|
14
|
+
reload(options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reload(options = {})
|
18
|
+
@rack_env = nil
|
19
|
+
instance_eval(File.read(config_file), config_file) if config_file && File.exists?(config_file)
|
20
|
+
validate(options) unless options[:validate] == false
|
21
|
+
end
|
22
|
+
|
23
|
+
#--------------------------------------------------------------------------
|
24
|
+
|
25
|
+
def rabbit(value = :missing)
|
26
|
+
if value == :missing
|
27
|
+
values[:rabbit] ||= {}.merge(DEFAULT_RABBIT)
|
28
|
+
elsif value.is_a?(Hash)
|
29
|
+
rabbit.merge!(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def config_file(value = :missing)
|
34
|
+
if value == :missing
|
35
|
+
values[:config_file]
|
36
|
+
else
|
37
|
+
values[:config_file] = filename(value)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def rack_file(value = :missing)
|
42
|
+
if value == :missing
|
43
|
+
values[:rack_file] ||= filename("config.ru", File.dirname(config_file || ""))
|
44
|
+
else
|
45
|
+
values[:rack_file] = filename(value, File.dirname(config_file || ""))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def queue(value = :missing)
|
50
|
+
if value == :missing
|
51
|
+
values[:queue]
|
52
|
+
else
|
53
|
+
values[:queue] = value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def exchange(value = :missing)
|
58
|
+
if value == :missing
|
59
|
+
values[:exchange]
|
60
|
+
else
|
61
|
+
values[:exchange] = value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def exchange_type(value = :missing)
|
66
|
+
if value == :missing
|
67
|
+
values[:exchange_type] ||= :direct
|
68
|
+
else
|
69
|
+
values[:exchange_type] = value.to_s.downcase.to_sym
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def routing_key(value = :missing)
|
74
|
+
if value == :missing
|
75
|
+
values[:routing_key]
|
76
|
+
else
|
77
|
+
values[:routing_key] = value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def app_id(value = :missing)
|
82
|
+
if value == :missing
|
83
|
+
values[:app_id] ||= "rr-#{exchange || 'default'}-#{queue || routing_key || 'null'}"
|
84
|
+
else
|
85
|
+
values[:app_id] = value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def workers(value = :missing)
|
90
|
+
if value == :missing
|
91
|
+
values[:workers] ||= 1
|
92
|
+
else
|
93
|
+
values[:workers] = value.to_i
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def min_workers(value = :missing)
|
98
|
+
if value == :missing
|
99
|
+
values[:min_workers] ||= 1
|
100
|
+
else
|
101
|
+
values[:min_workers] = value.to_i
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def max_workers(value = :missing)
|
106
|
+
if value == :missing
|
107
|
+
values[:max_workers] ||= 32
|
108
|
+
else
|
109
|
+
values[:max_workers] = value.to_i
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def ack(value = :missing)
|
114
|
+
if value == :missing
|
115
|
+
values[:ack]
|
116
|
+
else
|
117
|
+
values[:ack] = !!value
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def preload_app(value = :missing)
|
122
|
+
if value == :missing
|
123
|
+
values[:preload_app]
|
124
|
+
else
|
125
|
+
values[:preload_app] = !!value
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def daemonize(value = :missing)
|
130
|
+
if value == :missing
|
131
|
+
values[:daemonize]
|
132
|
+
else
|
133
|
+
values[:daemonize] = !!value
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def log_level(value = :missing)
|
138
|
+
if value == :missing
|
139
|
+
values[:log_level] ||= :info
|
140
|
+
else
|
141
|
+
values[:log_level] = symbolize(value)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def logger(value = :missing)
|
146
|
+
if value == :missing
|
147
|
+
values[:logger] ||= build_default_logger
|
148
|
+
else
|
149
|
+
values[:logger] = value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def logfile(value = :missing)
|
154
|
+
if value == :missing
|
155
|
+
values[:logfile] ||= daemonize ? "/var/log/#{app_id}.log" : nil
|
156
|
+
else
|
157
|
+
values[:logfile] = filename(value)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def pidfile(value = :missing)
|
162
|
+
if value == :missing
|
163
|
+
values[:pidfile] ||= daemonize ? "/var/run/#{app_id}.pid" : nil
|
164
|
+
else
|
165
|
+
values[:pidfile] = filename(value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def before_fork(server=nil, &block)
|
170
|
+
if block
|
171
|
+
values[:before_fork] = block
|
172
|
+
elsif values[:before_fork].respond_to?(:call)
|
173
|
+
values[:before_fork].call(server)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def after_fork(server=nil, worker=nil, &block)
|
178
|
+
if block
|
179
|
+
values[:after_fork] = block
|
180
|
+
elsif values[:after_fork].respond_to?(:call)
|
181
|
+
values[:after_fork].call(server, worker)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
#--------------------------------------------------------------------------
|
186
|
+
|
187
|
+
def rack_env
|
188
|
+
@rack_env ||= {
|
189
|
+
'rack.version' => Rack::VERSION,
|
190
|
+
'rack.logger' => logger,
|
191
|
+
'rack.errors' => $stderr,
|
192
|
+
'rack.multithread' => false,
|
193
|
+
'rack.multiprocess' => true,
|
194
|
+
'rack.run_once' => false,
|
195
|
+
'rack.url_scheme' => 'http',
|
196
|
+
'SERVER_NAME' => app_id
|
197
|
+
}
|
198
|
+
end
|
199
|
+
|
200
|
+
#--------------------------------------------------------------------------
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
attr_reader :values
|
205
|
+
|
206
|
+
def filename(path, relative_to = nil)
|
207
|
+
File.expand_path(path, relative_to)
|
208
|
+
end
|
209
|
+
|
210
|
+
def symbolize(s)
|
211
|
+
s.to_s.downcase.to_sym
|
212
|
+
end
|
213
|
+
|
214
|
+
def validate(options = {})
|
215
|
+
|
216
|
+
raise ArgumentError, "must provide EITHER a :queue OR an :exchange to subscribe to" if queue.nil? && exchange.nil?
|
217
|
+
raise ArgumentError, "missing app_id" if app_id.to_s.empty?
|
218
|
+
raise ArgumentError, "invalid workers" unless workers.is_a?(Fixnum)
|
219
|
+
raise ArgumentError, "invalid min_workers" unless min_workers.is_a?(Fixnum)
|
220
|
+
raise ArgumentError, "invalid max_workers" unless max_workers.is_a?(Fixnum)
|
221
|
+
raise ArgumentError, "invalid workers < min_workers" if workers < min_workers
|
222
|
+
raise ArgumentError, "invalid workers > max_workers" if workers > max_workers
|
223
|
+
raise ArgumentError, "invalid min_workers > max_workers" if min_workers > max_workers
|
224
|
+
raise ArgumentError, "invalid logger" unless [:fatal, :error, :warn, :info, :debug].all?{|method| logger.respond_to?(method)}
|
225
|
+
raise ArgumentError, "missing pidfile - required for daemon" if daemonize && pidfile.to_s.empty?
|
226
|
+
raise ArgumentError, "missing logfile - required for daemon" if daemonize && logfile.to_s.empty?
|
227
|
+
|
228
|
+
unless options[:skip_filesystem_checks]
|
229
|
+
raise ArgumentError, "missing rack config file #{rack_file}" unless File.readable?(rack_file)
|
230
|
+
raise ArgumentError, "pidfile not writable" if pidfile && !File.writable?(File.dirname(pidfile))
|
231
|
+
raise ArgumentError, "logfile not writable" if logfile && !File.writable?(File.dirname(logfile))
|
232
|
+
end
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
def build_default_logger
|
237
|
+
logger = Logger.new($stderr)
|
238
|
+
class << logger
|
239
|
+
attr_accessor :master_pid # track the master_pid (might change if we daemonize) in order to differentiate between "SERVER" vs "worker" in log entry preamble
|
240
|
+
end
|
241
|
+
logger.master_pid = $$
|
242
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
243
|
+
"[#{Process.pid}:#{$$ == logger.master_pid ? "SERVER" : "worker"}] #{datetime} #{msg}\n"
|
244
|
+
end
|
245
|
+
logger.level = case log_level.to_s.downcase.to_sym
|
246
|
+
when :fatal then Logger::FATAL
|
247
|
+
when :error then Logger::ERROR
|
248
|
+
when :warn then Logger::WARN
|
249
|
+
when :info then Logger::INFO
|
250
|
+
when :debug then Logger::DEBUG
|
251
|
+
else
|
252
|
+
Logger::INFO
|
253
|
+
end
|
254
|
+
logger
|
255
|
+
end
|
256
|
+
|
257
|
+
#--------------------------------------------------------------------------
|
258
|
+
|
259
|
+
end # class Config
|
260
|
+
end # module RackRabbit
|