Class: Jaws::Server
- Inherits:
-
Object
- Object
- Jaws::Server
- Defined in:
- lib/jaws/server.rb
Constant Summary collapse
- DefaultOptions =
{ :Host => '0.0.0.0', :Port => 8080, :MaxClients => 20, :SystemCores => nil, :ReadTimeout => 2, }
- DefaultRackEnv =
The default values for most of the rack environment variables
{ "rack.version" => [1,1], "rack.url_scheme" => "http", "rack.input" => StringIO.new, "rack.errors" => $stderr, "rack.multithread" => true, "rack.multiprocess" => false, "rack.run_once" => false, "SCRIPT_NAME" => "", "PATH_INFO" => "", "QUERY_STRING" => "", "SERVER_SOFTWARE" => "Rack+Jaws", }
- StatusStrings =
Rack::Utils::HTTP_STATUS_CODES
- CodesWithoutBody =
Rack::Utils::STATUS_WITH_NO_ENTITY_BODY
Instance Attribute Summary collapse
-
#host ⇒ Object
The host to listen on when run(app) is called.
-
#max_clients ⇒ Object
The maximum number of requests this server should handle concurrently.
-
#port ⇒ Object
The port to listen on when run(app) is called.
-
#read_timeout ⇒ Object
writeonly
The amount of time, in seconds, the server will wait without input before disconnecting the client.
-
#system_cores ⇒ Object
The number of cores the system has.
Instance Method Summary collapse
-
#chunked_read(io, timeout) ⇒ Object
Reads from a connection, yielding chunks of data as it goes, until the connection closes.
-
#initialize(options = DefaultOptions) ⇒ Server
constructor
Initializes a new Jaws server object.
-
#make_interruptable ⇒ Object
Sets the current thread as interruptable.
-
#run(app) ⇒ Object
Runs the application through the configured handler.
- #running? ⇒ Boolean
- #stop ⇒ Object
- #stopped? ⇒ Boolean
Constructor Details
#initialize(options = DefaultOptions) ⇒ Server
Initializes a new Jaws server object. Pass it a hash of options (:Host, :Port, :MaxClients, and :SystemCores valid)
66 67 68 69 70 71 72 |
# File 'lib/jaws/server.rb', line 66 def initialize( = DefaultOptions) @options = DefaultOptions.merge() DefaultOptions.each do |k,v| send(:"#{Jaws.decapse_name(k.to_s)}=", @options[k]) end self.extend Mutex_m end |
Instance Attribute Details
#host ⇒ Object
The host to listen on when run(app) is called. Also set with options
43 44 45 |
# File 'lib/jaws/server.rb', line 43 def host @host end |
#max_clients ⇒ Object
The maximum number of requests this server should handle concurrently. Also set with options Note that you should set this legitimately to the number of clients you can actually handle and not some arbitrary high number like with Mongrel. This server will simply not accept more connections than it can handle, which allows you to run other server instances on other machines to take up the slack. A really really good rule of thumb for a database driven site is to have it be less than the number of database connections your (hopefuly properly tuned) database server can handle. If you run more than one web server machine, the TOTAL max_clients from all those servers should be less than what the database can handle.
54 55 56 |
# File 'lib/jaws/server.rb', line 54 def max_clients @max_clients end |
#port ⇒ Object
The port to listen on when run(app) is called. Also set with options
45 46 47 |
# File 'lib/jaws/server.rb', line 45 def port @port end |
#read_timeout=(value) ⇒ Object
The amount of time, in seconds, the server will wait without input before disconnecting the client. Also set with options
63 64 65 |
# File 'lib/jaws/server.rb', line 63 def read_timeout=(value) @read_timeout = value end |
#system_cores ⇒ Object
The number of cores the system has. This may eventually be used to determine if the process should fork if it’s running on a ruby implementation that doesn’t support multiprocessing. If set to nil, it’ll auto-detect, and failing that just assume it shouldn’t fork at all. If you want it to never fork, you should set it to 1 (1 core means 1 process). Also set with options
60 61 62 |
# File 'lib/jaws/server.rb', line 60 def system_cores @system_cores end |
Instance Method Details
#chunked_read(io, timeout) ⇒ Object
Reads from a connection, yielding chunks of data as it goes, until the connection closes. Once the connection closes, it returns.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/jaws/server.rb', line 116 def chunked_read(io, timeout) begin loop do list = IO.select([io], [], [], @read_timeout) if (list.nil? || list.empty?) # IO.select tells us we timed out by giving us nil, # disconnect the non-talkative client. return end data = io.recv(4096) if (data == "") # If recv returns an empty string, that means the other # end closed the connection (either in response to our # end closing the write pipe or because they just felt # like it) so we close the connection from our end too. return end yield data end ensure io.close if (!io.closed?) end end |
#make_interruptable ⇒ Object
Sets the current thread as interruptable. This happens around the listen part of the thread. This means the thread is receptive to t.raise.
312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/jaws/server.rb', line 312 def make_interruptable begin @interruptable.synchronize do @interruptable << Thread.current end yield ensure @interruptable.synchronize do @interruptable.delete(Thread.current) end end end |
#run(app) ⇒ Object
Runs the application through the configured handler. Can only be run once at a time. If you try to run it more than once, the second run will block until the first finishes.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/jaws/server.rb', line 328 def run(app) synchronize do @interruptable = [] int_orig = trap "INT" do stop() end term_orig = trap "TERM" do stop() end begin @listener = create_listener(@options) @interruptable.extend Mutex_m if (@max_clients > 1) @master = Thread.current @workers = (0...@max_clients).collect do Thread.new do begin process_client(app) rescue GracefulExit, SystemExit => e # let it exit. rescue => e $stderr.puts("Handler thread unexpectedly died with #{e}:", e.backtrace) end end end @workers.each do |worker| worker.join end else begin @master = Thread.current @workers = [Thread.current] process_client(app) rescue GracefulExit, SystemExit => e # let it exit rescue => e $stderr.puts("Handler thread unexpectedly died with #{e}:", e.backtrace) end end ensure trap "INT", int_orig trap "TERM", term_orig @listener.close if (@listener && !@listener.closed?) @interruptable = @listener = @master = @workers = nil end end end |
#running? ⇒ Boolean
391 392 393 |
# File 'lib/jaws/server.rb', line 391 def running? !@workers.nil? end |
#stop ⇒ Object
376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/jaws/server.rb', line 376 def stop() # close the connection, the handler threads will exit # the next time they try to load. # TODO: Make it force them to exit after a timeout. $stderr.puts("Terminating request threads. To force immediate exit, send sigkill.") @interruptable.synchronize do @listener.close if !@listener.closed? @workers.each do |worker| if (@interruptable.include?(worker)) worker.raise GracefulExit, "Exiting" end end end end |
#stopped? ⇒ Boolean
394 395 396 |
# File 'lib/jaws/server.rb', line 394 def stopped? @workers.nil? end |