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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA512:
3
- metadata.gz: 179edb42ed70349903ee1c61dac5d041ce8ccf2224121e952871965635ea4f26541f58468c3f7bfc6842dfae80551993dae461845024e26a89bfbbfb315f144a
4
- data.tar.gz: dc50fc52dcabe5aaea8969654bdd1af13fc40cb1bd62ffaafc38a845b3fe1127a17b1f1adfcd2880a828a18241b869c5f4ad3782c71bcd40c5635d285e633a3a
3
+ data.tar.gz: b37cfd3f2c40682c86f0beb66377fa878e9e9afa7176607ef4c8d5ca342f6bbf5bc79be72e6f57a34d77730bead2c61af1c3cde5e336ede29fb1de4f3910528e
4
+ metadata.gz: db614d3e51992924e70599df591799d0437fc39790fdf279bf5f896db4dfab2d4f7da2f205d9d9cd1128aa120f6f7f14eb827a9cd3888fe2e9223188f5ddc21c
5
5
  SHA1:
6
- metadata.gz: da5833891f1c7570eb1cb642bbd506487eb2f3c8
7
- data.tar.gz: 3b093248ea8ac8cd931f1cb05db52d676a34494c
6
+ data.tar.gz: 982aa3206746b65d6fd27d6c285df134f78a8e80
7
+ metadata.gz: e351442a99e056e6b8779701e9357dcb306cf48a
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'pry', "~> 0.9.0"
6
- gem 'bson_ext'
6
+ gem 'bson_ext', '~>1.7'
data/bench/report.rb CHANGED
@@ -1,3 +1,5 @@
1
+ $LOAD_PATH.push(File.expand_path('../..', __FILE__))
2
+
1
3
  require 'benchmark'
2
4
  require 'bench/client'
3
5
 
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: 7600.3550ms
6
- Average Time: 0.7600ms
7
- Min Time: 0.3941ms
8
- Max Time: 38.5608ms
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: 9812
12
- 0.3ms: 15
13
- 0.4ms: 2030
14
- 0.5ms: 2816
15
- 0.6ms: 3236
16
- 0.7ms: 1250
17
- 0.8ms: 327
18
- 0.9ms: 138
19
- 1ms: 134
20
- 1.0ms: 60
21
- 1.1ms: 24
22
- 1.2ms: 16
23
- 1.3ms: 11
24
- 1.4ms: 5
25
- 1.5ms: 6
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
- 28ms: 1
37
- 30ms: 5
38
- 31ms: 14
39
- 32ms: 9
40
- 33ms: 7
41
- 34ms: 4
42
- 35ms: 2
43
- 36ms: 1
44
- 37ms: 1
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
- backtrace = exception.backtrace.join("\n")
105
- message = "#{exception.class}: #{exception.message}\n#{backtrace}"
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 :bad_request, :message => exception.message
48
+ build_response 400, :message => exception.message # BAD REQUEST
49
49
  elsif exception.kind_of?(Sanford::NotFoundError)
50
- build_response :not_found
50
+ build_response 404 # NOT FOUND
51
51
  elsif exception.kind_of?(Sanford::Protocol::TimeoutError)
52
- build_response :timeout
52
+ build_response 408 # TIMEOUT
53
53
  else
54
- build_response :error, :message => "An unexpected error occurred."
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
@@ -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
- attr_reader :server, :name, :pid_file, :restart_cmd
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
- @pid_file = PIDFile.new(@server.pid_file)
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
- @daemonize = !!options[:daemonize]
29
- @skip_daemonize = !ENV['SANFORD_SKIP_DAEMONIZE'].to_s.empty?
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
- ::Signal.trap("TERM"){ @server.stop }
44
- ::Signal.trap("INT"){ @server.halt }
45
- ::Signal.trap("USR2"){ @server.pause }
51
+ @signal_io.setup
52
+ trap_signals(@signal_io)
46
53
 
47
- thread = @server.start(@client_fds)
48
- log "#{@server.name} server started and ready."
49
- thread.join
50
- run_restart_cmd if @server.paused?
51
- rescue StandardError => exception
52
- log "Error: #{exception.message}"
53
- log "#{@server.name} server never started."
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 run_restart_cmd
69
- log "Restarting #{@server.name} daemon..."
70
- ENV['SANFORD_SERVER_FD'] = @server.file_descriptor.to_s
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
- def run
88
- Dir.chdir self.dir
89
- Kernel.exec(*self.argv)
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
@@ -24,6 +24,11 @@ module Sanford
24
24
  @routes.push(Sanford::Route.new(name, handler_name))
25
25
  end
26
26
 
27
+ def validate!
28
+ self.routes.each(&:validate!)
29
+ true
30
+ end
31
+
27
32
  def inspect
28
33
  reference = '0x0%x' % (self.object_id << 1)
29
34
  "#<#{self.class}:#{reference} " \
@@ -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, :dat_tcp_server
23
+ attr_reader :server_data
27
24
 
28
25
  def initialize
29
- self.class.configuration.validate!
30
- @server_data = ServerData.new(self.class.configuration.to_hash)
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
- @dat_tcp_server.listening? && !@dat_tcp_server.running?
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 configuration
132
- @configuration ||= Configuration.new
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 name(*args)
136
- self.configuration.name *args
170
+ def ip(value = nil)
171
+ self.config.ip = value if !value.nil?
172
+ self.config.ip
137
173
  end
138
174
 
139
- def ip(*args)
140
- self.configuration.ip *args
175
+ def port(value = nil)
176
+ self.config.port = value if !value.nil?
177
+ self.config.port
141
178
  end
142
179
 
143
- def port(*args)
144
- self.configuration.port *args
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 pid_file(*args)
148
- self.configuration.pid_file *args
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(new_worker_class = nil)
152
- self.configuration.worker_class = new_worker_class if new_worker_class
153
- self.configuration.worker_class
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(new_worker_params = nil)
157
- self.configuration.worker_params = new_worker_params if new_worker_params
158
- self.configuration.worker_params
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.configuration.num_workers = new_num_workers if new_num_workers
163
- self.configuration.num_workers
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 receives_keep_alive(*args)
168
- self.configuration.receives_keep_alive *args
206
+ def init(&block)
207
+ self.config.init_procs << block
169
208
  end
170
209
 
171
- def verbose_logging(*args)
172
- self.configuration.verbose_logging *args
210
+ def error(&block)
211
+ self.config.error_procs << block
173
212
  end
174
213
 
175
- def logger(*args)
176
- self.configuration.logger *args
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 shutdown_timeout(new_timeout = nil)
180
- self.configuration.shutdown_timeout = new_timeout if new_timeout
181
- self.configuration.shutdown_timeout
219
+ def logger(value = nil)
220
+ self.config.logger = value if !value.nil?
221
+ self.config.logger
182
222
  end
183
223
 
184
- def init(&block)
185
- self.configuration.init_procs << block
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
- def error(&block)
189
- self.configuration.error_procs << block
190
- end
230
+ # flags
191
231
 
192
- def router(value = nil, &block)
193
- self.configuration.router = value if !value.nil?
194
- self.configuration.router.instance_eval(&block) if block
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 template_source(*args)
199
- self.configuration.template_source(*args)
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 Configuration
205
- include NsOptions::Proxy
206
-
207
- DEFAULT_NUM_WORKERS = 4
244
+ class Config
208
245
 
209
- option :name, String, :required => true
210
- option :ip, String, :required => true, :default => '0.0.0.0'
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
- option :receives_keep_alive, NsOptions::Boolean, :default => false
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 :shutdown_timeout
223
- attr_accessor :router
251
+ attr_accessor :init_procs, :error_procs, :template_source, :logger, :router
252
+ attr_accessor :receives_keep_alive, :verbose_logging
224
253
 
225
- def initialize(values = nil)
226
- super(values)
227
- @init_procs, @error_procs = [], []
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
- @shutdown_timeout = nil
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
- @valid = nil
268
+
269
+ @receives_keep_alive = false
270
+ @verbose_logging = true
271
+
272
+ @valid = nil
234
273
  end
235
274
 
236
275
  def routes
237
- @router.routes
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
- if !self.required_set?
261
- raise InvalidError, "a name, ip and port must be configured"
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
- self.routes.each(&:validate!)
267
- @valid = true
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