sanford 0.17.0 → 0.18.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 +4 -4
- data/Gemfile +1 -1
- data/bench/report.rb +2 -0
- data/bench/report.txt +28 -37
- data/lib/sanford/connection_handler.rb +10 -3
- data/lib/sanford/error_handler.rb +4 -4
- data/lib/sanford/io_pipe.rb +40 -0
- data/lib/sanford/process.rb +108 -28
- data/lib/sanford/router.rb +5 -0
- data/lib/sanford/server.rb +133 -95
- data/lib/sanford/server_data.rb +27 -28
- data/lib/sanford/template_source.rb +2 -2
- data/lib/sanford/version.rb +1 -1
- data/sanford.gemspec +4 -5
- data/test/helper.rb +11 -0
- data/test/support/app_server.rb +6 -3
- data/test/support/factory.rb +7 -0
- data/test/system/server_tests.rb +21 -3
- data/test/system/service_handler_tests.rb +4 -4
- data/test/unit/cli_tests.rb +2 -2
- data/test/unit/connection_handler_tests.rb +107 -47
- data/test/unit/error_handler_tests.rb +11 -11
- data/test/unit/io_pipe_tests.rb +84 -0
- data/test/unit/process_tests.rb +266 -131
- data/test/unit/router_tests.rb +25 -7
- data/test/unit/server_data_tests.rb +68 -46
- data/test/unit/server_tests.rb +197 -240
- data/test/unit/template_engine_tests.rb +1 -1
- data/test/unit/template_source_tests.rb +6 -0
- data/test/unit/test_runner_tests.rb +0 -19
- metadata +12 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA512:
|
3
|
-
|
4
|
-
|
3
|
+
data.tar.gz: b37cfd3f2c40682c86f0beb66377fa878e9e9afa7176607ef4c8d5ca342f6bbf5bc79be72e6f57a34d77730bead2c61af1c3cde5e336ede29fb1de4f3910528e
|
4
|
+
metadata.gz: db614d3e51992924e70599df591799d0437fc39790fdf279bf5f896db4dfab2d4f7da2f205d9d9cd1128aa120f6f7f14eb827a9cd3888fe2e9223188f5ddc21c
|
5
5
|
SHA1:
|
6
|
-
|
7
|
-
|
6
|
+
data.tar.gz: 982aa3206746b65d6fd27d6c285df134f78a8e80
|
7
|
+
metadata.gz: e351442a99e056e6b8779701e9357dcb306cf48a
|
data/Gemfile
CHANGED
data/bench/report.rb
CHANGED
data/bench/report.txt
CHANGED
@@ -2,46 +2,37 @@ Running benchmark report...
|
|
2
2
|
|
3
3
|
Hitting "simple" service with {}, 10000 times
|
4
4
|
....................................................................................................
|
5
|
-
Total Time:
|
6
|
-
Average Time: 0.
|
7
|
-
Min Time: 0.
|
8
|
-
Max Time:
|
5
|
+
Total Time: 7117.6994ms
|
6
|
+
Average Time: 0.7117ms
|
7
|
+
Min Time: 0.4079ms
|
8
|
+
Max Time: 71.8839ms
|
9
9
|
|
10
10
|
Distribution (number of requests):
|
11
|
-
0ms:
|
12
|
-
0.
|
13
|
-
0.
|
14
|
-
0.
|
15
|
-
0.
|
16
|
-
0.
|
17
|
-
0.
|
18
|
-
|
19
|
-
|
20
|
-
1.
|
21
|
-
1.
|
22
|
-
1.
|
23
|
-
1.
|
24
|
-
1.
|
25
|
-
|
26
|
-
1.6ms: 5
|
27
|
-
1.7ms: 4
|
28
|
-
1.8ms: 2
|
29
|
-
1.9ms: 1
|
30
|
-
2ms: 4
|
31
|
-
6ms: 1
|
32
|
-
7ms: 1
|
11
|
+
0ms: 9917
|
12
|
+
0.4ms: 2569
|
13
|
+
0.5ms: 2754
|
14
|
+
0.6ms: 2608
|
15
|
+
0.7ms: 1654
|
16
|
+
0.8ms: 262
|
17
|
+
0.9ms: 70
|
18
|
+
1ms: 62
|
19
|
+
1.0ms: 31
|
20
|
+
1.1ms: 17
|
21
|
+
1.2ms: 7
|
22
|
+
1.3ms: 5
|
23
|
+
1.5ms: 1
|
24
|
+
1.8ms: 1
|
25
|
+
3ms: 1
|
33
26
|
8ms: 1
|
34
|
-
9ms: 1
|
35
27
|
10ms: 1
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
38ms: 1
|
28
|
+
27ms: 1
|
29
|
+
41ms: 1
|
30
|
+
47ms: 1
|
31
|
+
65ms: 4
|
32
|
+
66ms: 1
|
33
|
+
67ms: 5
|
34
|
+
68ms: 3
|
35
|
+
70ms: 1
|
36
|
+
71ms: 1
|
46
37
|
|
47
38
|
Done running benchmark report
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'benchmark'
|
2
|
+
require 'dat-worker-pool'
|
2
3
|
require 'sanford-protocol'
|
3
4
|
require 'sanford/error_handler'
|
4
5
|
require 'sanford/logger'
|
@@ -45,6 +46,11 @@ module Sanford
|
|
45
46
|
|
46
47
|
response = route.run(request, @server_data)
|
47
48
|
processed_service.response = response
|
49
|
+
rescue DatWorkerPool::ShutdownError => exception
|
50
|
+
error = ShutdownError.new(exception.message)
|
51
|
+
error.set_backtrace(exception.backtrace)
|
52
|
+
self.handle_exception(error, @server_data, processed_service)
|
53
|
+
raise exception
|
48
54
|
rescue StandardError => exception
|
49
55
|
self.handle_exception(exception, @server_data, processed_service)
|
50
56
|
ensure
|
@@ -101,9 +107,8 @@ module Sanford
|
|
101
107
|
end
|
102
108
|
|
103
109
|
def log_exception(exception)
|
104
|
-
|
105
|
-
|
106
|
-
log_verbose(message, :error)
|
110
|
+
log_verbose("#{exception.class}: #{exception.message}", :error)
|
111
|
+
(exception.backtrace || []).each{ |l| log_verbose(l, :error) }
|
107
112
|
end
|
108
113
|
|
109
114
|
def log_verbose(message, level = :info)
|
@@ -154,4 +159,6 @@ module Sanford
|
|
154
159
|
|
155
160
|
end
|
156
161
|
|
162
|
+
ShutdownError = Class.new(DatWorkerPool::ShutdownError)
|
163
|
+
|
157
164
|
end
|
@@ -45,13 +45,13 @@ module Sanford
|
|
45
45
|
def response_from_exception(exception)
|
46
46
|
if exception.kind_of?(Sanford::Protocol::BadMessageError) ||
|
47
47
|
exception.kind_of?(Sanford::Protocol::Request::InvalidError)
|
48
|
-
build_response
|
48
|
+
build_response 400, :message => exception.message # BAD REQUEST
|
49
49
|
elsif exception.kind_of?(Sanford::NotFoundError)
|
50
|
-
build_response
|
50
|
+
build_response 404 # NOT FOUND
|
51
51
|
elsif exception.kind_of?(Sanford::Protocol::TimeoutError)
|
52
|
-
build_response
|
52
|
+
build_response 408 # TIMEOUT
|
53
53
|
else
|
54
|
-
build_response
|
54
|
+
build_response 500, :message => "An unexpected error occurred." # ERROR
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sanford
|
2
|
+
|
3
|
+
class IOPipe
|
4
|
+
|
5
|
+
NULL = File.open('/dev/null', 'w')
|
6
|
+
NUMBER_OF_BYTES = 1
|
7
|
+
|
8
|
+
attr_reader :reader, :writer
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@reader = NULL
|
12
|
+
@writer = NULL
|
13
|
+
end
|
14
|
+
|
15
|
+
def setup
|
16
|
+
@reader, @writer = ::IO.pipe
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
@reader.close unless @reader === NULL
|
21
|
+
@writer.close unless @writer === NULL
|
22
|
+
@reader = NULL
|
23
|
+
@writer = NULL
|
24
|
+
end
|
25
|
+
|
26
|
+
def read
|
27
|
+
@reader.read_nonblock(NUMBER_OF_BYTES)
|
28
|
+
end
|
29
|
+
|
30
|
+
def write(value)
|
31
|
+
@writer.write_nonblock(value[0, NUMBER_OF_BYTES])
|
32
|
+
end
|
33
|
+
|
34
|
+
def wait(timeout = nil)
|
35
|
+
!!::IO.select([@reader], nil, nil, timeout)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/sanford/process.rb
CHANGED
@@ -1,17 +1,27 @@
|
|
1
|
+
require 'sanford/io_pipe'
|
1
2
|
require 'sanford/pid_file'
|
2
3
|
|
3
4
|
module Sanford
|
4
5
|
|
5
6
|
class Process
|
6
7
|
|
7
|
-
|
8
|
+
HALT = 'H'.freeze
|
9
|
+
STOP = 'S'.freeze
|
10
|
+
RESTART = 'R'.freeze
|
11
|
+
|
12
|
+
WAIT_FOR_SIGNALS_TIMEOUT = 15
|
13
|
+
|
14
|
+
attr_reader :server, :name, :pid_file, :signal_io, :restart_cmd
|
8
15
|
attr_reader :server_ip, :server_port, :server_fd, :client_fds
|
9
16
|
|
10
17
|
def initialize(server, options = nil)
|
11
18
|
options ||= {}
|
12
19
|
@server = server
|
20
|
+
@name = "sanford: #{@server.process_label}"
|
13
21
|
@logger = @server.logger
|
14
|
-
|
22
|
+
|
23
|
+
@pid_file = PIDFile.new(@server.pid_file)
|
24
|
+
@signal_io = IOPipe.new
|
15
25
|
@restart_cmd = RestartCmd.new
|
16
26
|
|
17
27
|
@server_ip = @server.configured_ip
|
@@ -21,12 +31,10 @@ module Sanford
|
|
21
31
|
end
|
22
32
|
@listen_args = @server_fd ? [@server_fd] : [@server_ip, @server_port]
|
23
33
|
|
24
|
-
@name = "sanford-#{@server.name}-#{@server_ip}-#{@server_port}"
|
25
|
-
|
26
34
|
@client_fds = ENV['SANFORD_CLIENT_FDS'].to_s.split(',').map(&:to_i)
|
27
35
|
|
28
|
-
|
29
|
-
@
|
36
|
+
skip_daemonize = ignore_if_blank(ENV['SANFORD_SKIP_DAEMONIZE'])
|
37
|
+
@daemonize = !!options[:daemonize] && !skip_daemonize
|
30
38
|
end
|
31
39
|
|
32
40
|
def run
|
@@ -40,37 +48,82 @@ module Sanford
|
|
40
48
|
@pid_file.write
|
41
49
|
log "PID: #{@pid_file.pid}"
|
42
50
|
|
43
|
-
|
44
|
-
|
45
|
-
::Signal.trap("USR2"){ @server.pause }
|
51
|
+
@signal_io.setup
|
52
|
+
trap_signals(@signal_io)
|
46
53
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
+
start_server(@server, @client_fds)
|
55
|
+
|
56
|
+
signal = catch(:signal) do
|
57
|
+
wait_for_signals(@signal_io, @server)
|
58
|
+
end
|
59
|
+
@signal_io.teardown
|
60
|
+
|
61
|
+
run_restart_cmd(@restart_cmd, @server) if signal == RESTART
|
54
62
|
ensure
|
55
63
|
@pid_file.remove
|
56
64
|
end
|
57
65
|
|
58
|
-
def daemonize
|
59
|
-
@daemonize && !@skip_daemonize
|
60
|
-
end
|
66
|
+
def daemonize?; @daemonize; end
|
61
67
|
|
62
68
|
private
|
63
69
|
|
70
|
+
def start_server(server, client_fds)
|
71
|
+
server.start(client_fds)
|
72
|
+
log "#{server.name} server started and ready."
|
73
|
+
rescue StandardError => exception
|
74
|
+
log "#{server.name} server never started."
|
75
|
+
raise exception
|
76
|
+
end
|
77
|
+
|
78
|
+
def trap_signals(signal_io)
|
79
|
+
trap_signal('INT'){ signal_io.write(HALT) }
|
80
|
+
trap_signal('TERM'){ signal_io.write(STOP) }
|
81
|
+
trap_signal('USR2'){ signal_io.write(RESTART) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def trap_signal(signal, &block)
|
85
|
+
::Signal.trap(signal, &block)
|
86
|
+
rescue ArgumentError
|
87
|
+
log "'#{signal}' signal not supported"
|
88
|
+
end
|
89
|
+
|
90
|
+
def wait_for_signals(signal_io, server)
|
91
|
+
loop do
|
92
|
+
ready = signal_io.wait(WAIT_FOR_SIGNALS_TIMEOUT)
|
93
|
+
handle_signal(signal_io.read, server) if ready
|
94
|
+
|
95
|
+
if !server.running?
|
96
|
+
log "Server crashed, restarting"
|
97
|
+
start_server(server, server.client_file_descriptors)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_signal(signal, server)
|
103
|
+
log "Got '#{signal}' signal"
|
104
|
+
case signal
|
105
|
+
when HALT
|
106
|
+
server.halt(true)
|
107
|
+
when STOP
|
108
|
+
server.stop(true)
|
109
|
+
when RESTART
|
110
|
+
server.pause(true)
|
111
|
+
end
|
112
|
+
throw :signal, signal
|
113
|
+
end
|
114
|
+
|
115
|
+
def run_restart_cmd(restart_cmd, server)
|
116
|
+
log "Restarting #{server.name} daemon..."
|
117
|
+
restart_cmd.run(server)
|
118
|
+
end
|
119
|
+
|
64
120
|
def log(message)
|
65
121
|
@logger.info "[Sanford] #{message}"
|
66
122
|
end
|
67
123
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
ENV['SANFORD_CLIENT_FDS'] = @server.client_file_descriptors.join(',')
|
72
|
-
ENV['SANFORD_SKIP_DAEMONIZE'] = 'yes'
|
73
|
-
@restart_cmd.run
|
124
|
+
def ignore_if_blank(value, &block)
|
125
|
+
block ||= proc{ |v| v }
|
126
|
+
block.call(value) if value && !value.empty?
|
74
127
|
end
|
75
128
|
|
76
129
|
end
|
@@ -84,9 +137,36 @@ module Sanford
|
|
84
137
|
@argv = [Gem.ruby, $0, ARGV.dup].flatten
|
85
138
|
end
|
86
139
|
|
87
|
-
|
88
|
-
|
89
|
-
|
140
|
+
if RUBY_VERSION == '1.8.7'
|
141
|
+
|
142
|
+
def run(server)
|
143
|
+
ENV['SANFORD_SERVER_FD'] = server.file_descriptor.to_s
|
144
|
+
ENV['SANFORD_CLIENT_FDS'] = server.client_file_descriptors.join(',')
|
145
|
+
ENV['SANFORD_SKIP_DAEMONIZE'] = 'yes'
|
146
|
+
Dir.chdir self.dir
|
147
|
+
Kernel.exec(*self.argv)
|
148
|
+
end
|
149
|
+
|
150
|
+
else
|
151
|
+
|
152
|
+
def run(server)
|
153
|
+
env = {
|
154
|
+
'SANFORD_SERVER_FD' => server.file_descriptor.to_s,
|
155
|
+
'SANFORD_CLIENT_FDS' => server.client_file_descriptors.join(','),
|
156
|
+
'SANFORD_SKIP_DAEMONIZE' => 'yes'
|
157
|
+
}
|
158
|
+
# in ruby 1.9+ the `Kernel.exec` method is passed file descriptor
|
159
|
+
# redirects, this makes it so the child process that we are running via
|
160
|
+
# the `exec` has access to the file descriptors and can open them
|
161
|
+
fd_redirects = (
|
162
|
+
[server.file_descriptor] +
|
163
|
+
server.client_file_descriptors
|
164
|
+
).inject({}){ |h, fd| h.merge!(fd => fd) }
|
165
|
+
options = { :chdir => self.dir }.merge!(fd_redirects)
|
166
|
+
|
167
|
+
Kernel.exec(*([env] + self.argv + [options]))
|
168
|
+
end
|
169
|
+
|
90
170
|
end
|
91
171
|
|
92
172
|
private
|
data/lib/sanford/router.rb
CHANGED
data/lib/sanford/server.rb
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
require 'dat-tcp'
|
2
2
|
require 'much-plugin'
|
3
|
-
require 'ns-options'
|
4
|
-
require 'ns-options/boolean'
|
5
|
-
require 'pathname'
|
6
3
|
require 'sanford-protocol'
|
7
4
|
require 'socket'
|
8
5
|
require 'sanford/logger'
|
@@ -23,11 +20,35 @@ module Sanford
|
|
23
20
|
|
24
21
|
module InstanceMethods
|
25
22
|
|
26
|
-
attr_reader :server_data
|
23
|
+
attr_reader :server_data
|
27
24
|
|
28
25
|
def initialize
|
29
|
-
self.class.
|
30
|
-
|
26
|
+
config = self.class.config
|
27
|
+
begin
|
28
|
+
config.validate!
|
29
|
+
rescue InvalidError => exception
|
30
|
+
exception.set_backtrace(caller)
|
31
|
+
raise exception
|
32
|
+
end
|
33
|
+
|
34
|
+
@server_data = ServerData.new({
|
35
|
+
:name => config.name,
|
36
|
+
:ip => config.ip,
|
37
|
+
:port => config.port,
|
38
|
+
:pid_file => config.pid_file,
|
39
|
+
:shutdown_timeout => config.shutdown_timeout,
|
40
|
+
:worker_class => config.worker_class,
|
41
|
+
:worker_params => config.worker_params,
|
42
|
+
:num_workers => config.num_workers,
|
43
|
+
:error_procs => config.error_procs,
|
44
|
+
:template_source => config.template_source,
|
45
|
+
:logger => config.logger,
|
46
|
+
:router => config.router,
|
47
|
+
:receives_keep_alive => config.receives_keep_alive,
|
48
|
+
:verbose_logging => config.verbose_logging,
|
49
|
+
:routes => config.routes
|
50
|
+
})
|
51
|
+
|
31
52
|
@dat_tcp_server = DatTCP::Server.new(self.server_data.worker_class, {
|
32
53
|
:num_workers => self.server_data.num_workers,
|
33
54
|
:logger => self.server_data.dtcp_logger,
|
@@ -36,13 +57,6 @@ module Sanford
|
|
36
57
|
:sanford_server_data => self.server_data
|
37
58
|
})
|
38
59
|
})
|
39
|
-
rescue InvalidError => exception
|
40
|
-
exception.set_backtrace(caller)
|
41
|
-
raise exception
|
42
|
-
end
|
43
|
-
|
44
|
-
def name
|
45
|
-
@server_data.name
|
46
60
|
end
|
47
61
|
|
48
62
|
def ip
|
@@ -61,6 +75,10 @@ module Sanford
|
|
61
75
|
@dat_tcp_server.client_file_descriptors
|
62
76
|
end
|
63
77
|
|
78
|
+
def name
|
79
|
+
@server_data.name
|
80
|
+
end
|
81
|
+
|
64
82
|
def configured_ip
|
65
83
|
@server_data.ip
|
66
84
|
end
|
@@ -69,6 +87,10 @@ module Sanford
|
|
69
87
|
@server_data.port
|
70
88
|
end
|
71
89
|
|
90
|
+
def process_label
|
91
|
+
@server_data.process_label
|
92
|
+
end
|
93
|
+
|
72
94
|
def pid_file
|
73
95
|
@server_data.pid_file
|
74
96
|
end
|
@@ -110,8 +132,16 @@ module Sanford
|
|
110
132
|
@dat_tcp_server.halt(*args)
|
111
133
|
end
|
112
134
|
|
135
|
+
def listening?
|
136
|
+
@dat_tcp_server.listening?
|
137
|
+
end
|
138
|
+
|
139
|
+
def running?
|
140
|
+
@dat_tcp_server.running?
|
141
|
+
end
|
142
|
+
|
113
143
|
def paused?
|
114
|
-
|
144
|
+
self.listening? && !self.running?
|
115
145
|
end
|
116
146
|
|
117
147
|
private
|
@@ -128,149 +158,157 @@ module Sanford
|
|
128
158
|
|
129
159
|
module ClassMethods
|
130
160
|
|
131
|
-
def
|
132
|
-
@
|
161
|
+
def config
|
162
|
+
@config ||= Config.new
|
163
|
+
end
|
164
|
+
|
165
|
+
def name(value = nil)
|
166
|
+
self.config.name = value if !value.nil?
|
167
|
+
self.config.name
|
133
168
|
end
|
134
169
|
|
135
|
-
def
|
136
|
-
self.
|
170
|
+
def ip(value = nil)
|
171
|
+
self.config.ip = value if !value.nil?
|
172
|
+
self.config.ip
|
137
173
|
end
|
138
174
|
|
139
|
-
def
|
140
|
-
self.
|
175
|
+
def port(value = nil)
|
176
|
+
self.config.port = value if !value.nil?
|
177
|
+
self.config.port
|
141
178
|
end
|
142
179
|
|
143
|
-
def
|
144
|
-
self.
|
180
|
+
def pid_file(value = nil)
|
181
|
+
self.config.pid_file = value if !value.nil?
|
182
|
+
self.config.pid_file
|
145
183
|
end
|
146
184
|
|
147
|
-
def
|
148
|
-
self.
|
185
|
+
def shutdown_timeout(value = nil)
|
186
|
+
self.config.shutdown_timeout = value if !value.nil?
|
187
|
+
self.config.shutdown_timeout
|
149
188
|
end
|
150
189
|
|
151
|
-
def worker_class(
|
152
|
-
self.
|
153
|
-
self.
|
190
|
+
def worker_class(value = nil)
|
191
|
+
self.config.worker_class = value if !value.nil?
|
192
|
+
self.config.worker_class
|
154
193
|
end
|
155
194
|
|
156
|
-
def worker_params(
|
157
|
-
self.
|
158
|
-
self.
|
195
|
+
def worker_params(value = nil)
|
196
|
+
self.config.worker_params = value if !value.nil?
|
197
|
+
self.config.worker_params
|
159
198
|
end
|
160
199
|
|
161
200
|
def num_workers(new_num_workers = nil)
|
162
|
-
self.
|
163
|
-
self.
|
201
|
+
self.config.num_workers = new_num_workers if new_num_workers
|
202
|
+
self.config.num_workers
|
164
203
|
end
|
165
204
|
alias :workers :num_workers
|
166
205
|
|
167
|
-
def
|
168
|
-
self.
|
206
|
+
def init(&block)
|
207
|
+
self.config.init_procs << block
|
169
208
|
end
|
170
209
|
|
171
|
-
def
|
172
|
-
self.
|
210
|
+
def error(&block)
|
211
|
+
self.config.error_procs << block
|
173
212
|
end
|
174
213
|
|
175
|
-
def
|
176
|
-
self.
|
214
|
+
def template_source(value = nil)
|
215
|
+
self.config.template_source = value if !value.nil?
|
216
|
+
self.config.template_source
|
177
217
|
end
|
178
218
|
|
179
|
-
def
|
180
|
-
self.
|
181
|
-
self.
|
219
|
+
def logger(value = nil)
|
220
|
+
self.config.logger = value if !value.nil?
|
221
|
+
self.config.logger
|
182
222
|
end
|
183
223
|
|
184
|
-
def
|
185
|
-
self.
|
224
|
+
def router(value = nil, &block)
|
225
|
+
self.config.router = value if !value.nil?
|
226
|
+
self.config.router.instance_eval(&block) if block
|
227
|
+
self.config.router
|
186
228
|
end
|
187
229
|
|
188
|
-
|
189
|
-
self.configuration.error_procs << block
|
190
|
-
end
|
230
|
+
# flags
|
191
231
|
|
192
|
-
def
|
193
|
-
self.
|
194
|
-
self.
|
195
|
-
self.configuration.router
|
232
|
+
def receives_keep_alive(value = nil)
|
233
|
+
self.config.receives_keep_alive = value if !value.nil?
|
234
|
+
self.config.receives_keep_alive
|
196
235
|
end
|
197
236
|
|
198
|
-
def
|
199
|
-
self.
|
237
|
+
def verbose_logging(value = nil)
|
238
|
+
self.config.verbose_logging = value if !value.nil?
|
239
|
+
self.config.verbose_logging
|
200
240
|
end
|
201
241
|
|
202
242
|
end
|
203
243
|
|
204
|
-
class
|
205
|
-
include NsOptions::Proxy
|
206
|
-
|
207
|
-
DEFAULT_NUM_WORKERS = 4
|
244
|
+
class Config
|
208
245
|
|
209
|
-
|
210
|
-
|
211
|
-
option :port, Integer, :required => true
|
212
|
-
option :pid_file, Pathname
|
246
|
+
DEFAULT_NUM_WORKERS = 4.freeze
|
247
|
+
DEFAULT_IP_ADDRESS = '0.0.0.0'.freeze
|
213
248
|
|
214
|
-
|
215
|
-
|
216
|
-
option :verbose_logging, :default => true
|
217
|
-
option :logger, :default => proc{ NullLogger.new }
|
218
|
-
option :template_source, :default => proc{ NullTemplateSource.new }
|
219
|
-
|
220
|
-
attr_accessor :init_procs, :error_procs
|
249
|
+
attr_accessor :name, :ip, :port, :pid_file, :shutdown_timeout
|
221
250
|
attr_accessor :worker_class, :worker_params, :num_workers
|
222
|
-
attr_accessor :
|
223
|
-
attr_accessor :
|
251
|
+
attr_accessor :init_procs, :error_procs, :template_source, :logger, :router
|
252
|
+
attr_accessor :receives_keep_alive, :verbose_logging
|
224
253
|
|
225
|
-
def initialize
|
226
|
-
|
227
|
-
@
|
254
|
+
def initialize
|
255
|
+
@name = nil
|
256
|
+
@ip = DEFAULT_IP_ADDRESS
|
257
|
+
@port = nil
|
258
|
+
@pid_file = nil
|
259
|
+
@shutdown_timeout = nil
|
228
260
|
@worker_class = DefaultWorker
|
229
261
|
@worker_params = nil
|
230
262
|
@num_workers = DEFAULT_NUM_WORKERS
|
231
|
-
@
|
263
|
+
@init_procs = []
|
264
|
+
@error_procs = []
|
265
|
+
@template_source = Sanford::NullTemplateSource.new(ENV['PWD'])
|
266
|
+
@logger = Sanford::NullLogger.new
|
232
267
|
@router = Sanford::Router.new
|
233
|
-
|
268
|
+
|
269
|
+
@receives_keep_alive = false
|
270
|
+
@verbose_logging = true
|
271
|
+
|
272
|
+
@valid = nil
|
234
273
|
end
|
235
274
|
|
236
275
|
def routes
|
237
|
-
|
238
|
-
end
|
239
|
-
|
240
|
-
def to_hash
|
241
|
-
super.merge({
|
242
|
-
:init_procs => self.init_procs,
|
243
|
-
:error_procs => self.error_procs,
|
244
|
-
:worker_class => self.worker_class,
|
245
|
-
:worker_params => self.worker_params,
|
246
|
-
:num_workers => self.num_workers,
|
247
|
-
:shutdown_timeout => self.shutdown_timeout,
|
248
|
-
:router => self.router,
|
249
|
-
:routes => self.routes
|
250
|
-
})
|
276
|
+
self.router.routes
|
251
277
|
end
|
252
278
|
|
253
279
|
def valid?
|
254
280
|
!!@valid
|
255
281
|
end
|
256
282
|
|
283
|
+
# for the config to be considered "valid", a few things need to happen.
|
284
|
+
# The key here is that this only needs to be done _once_ for each config.
|
285
|
+
|
257
286
|
def validate!
|
258
|
-
return @valid if !@valid.nil?
|
287
|
+
return @valid if !@valid.nil? # only need to run this once per config
|
288
|
+
|
289
|
+
# ensure all user and plugin configs/settings are applied
|
259
290
|
self.init_procs.each(&:call)
|
260
|
-
|
261
|
-
|
291
|
+
[:name, :ip, :port].each do |a|
|
292
|
+
if self.send(a).nil?
|
293
|
+
raise InvalidError, "a name, ip and port must be configured"
|
294
|
+
end
|
262
295
|
end
|
296
|
+
|
297
|
+
# validate the worker class
|
263
298
|
if !self.worker_class.kind_of?(Class) || !self.worker_class.include?(Sanford::Worker)
|
264
299
|
raise InvalidError, "worker class must include `#{Sanford::Worker}`"
|
265
300
|
end
|
266
|
-
|
267
|
-
|
301
|
+
|
302
|
+
# validate the router
|
303
|
+
self.router.validate!
|
304
|
+
|
305
|
+
@valid = true # if it made it this far, it's valid!
|
268
306
|
end
|
307
|
+
|
269
308
|
end
|
270
309
|
|
271
310
|
DefaultWorker = Class.new{ include Sanford::Worker }
|
272
|
-
|
273
|
-
InvalidError = Class.new(RuntimeError)
|
311
|
+
InvalidError = Class.new(RuntimeError)
|
274
312
|
|
275
313
|
end
|
276
314
|
|