Class: Jaws::Server

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(options = DefaultOptions) ⇒ Server

Initializes a new Jaws server object. Pass it a hash of options (:Host, :Port, :MaxClients, and :SystemCores valid)



65
66
67
68
69
70
71
# File 'lib/jaws/server.rb', line 65

def initialize(options = DefaultOptions)
  @options = DefaultOptions.merge(options)
  DefaultOptions.each do |k,v|
    send(:"#{Jaws.decapse_name(k.to_s)}=", @options[k])
  end
  self.extend Mutex_m
end

Instance Attribute Details

#hostObject

The host to listen on when run(app) is called. Also set with options



42
43
44
# File 'lib/jaws/server.rb', line 42

def host
  @host
end

#max_clientsObject

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.



53
54
55
# File 'lib/jaws/server.rb', line 53

def max_clients
  @max_clients
end

#portObject

The port to listen on when run(app) is called. Also set with options



44
45
46
# File 'lib/jaws/server.rb', line 44

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



62
63
64
# File 'lib/jaws/server.rb', line 62

def read_timeout=(value)
  @read_timeout = value
end

#system_coresObject

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



59
60
61
# File 'lib/jaws/server.rb', line 59

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.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/jaws/server.rb', line 114

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

#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.



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/jaws/server.rb', line 305

def run(app)
  synchronize do
    begin
      @listener = create_listener(@options)
      if (@max_clients > 1)
        @master = Thread.current
        @workers = (0...@max_clients).collect do
          Thread.new do
            process_client(app)
          end
        end
        @workers.each do |worker|
          worker.join
        end
      else
        @master = Thread.current
        @workers = [Thread.current]
        process_client(app)
      end      
    ensure
      @listener.close if (@listener && !@listener.closed?)
      @listener = @master = @workers = nil
    end
  end
end

#running?Boolean

Returns:

  • (Boolean)


338
339
340
# File 'lib/jaws/server.rb', line 338

def running?
  !@workers.nil?
end

#stopObject



331
332
333
334
335
336
# File 'lib/jaws/server.rb', line 331

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.
  @listener.close if !@listener.closed?
end

#stopped?Boolean

Returns:

  • (Boolean)


341
342
343
# File 'lib/jaws/server.rb', line 341

def stopped?
  @workers.nil?
end