mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #37037 from Sean0628/update-initialization-page
Update The Rails Initialization Process page[ci skip]
This commit is contained in:
commit
b67785a476
1 changed files with 276 additions and 242 deletions
|
@ -133,7 +133,7 @@ Once `config/boot.rb` has finished, the next file that is required is
|
|||
`ARGV` array simply contains `server` which will be passed over:
|
||||
|
||||
```ruby
|
||||
require_relative "command"
|
||||
require "rails/command"
|
||||
|
||||
aliases = {
|
||||
"g" => "generate",
|
||||
|
@ -166,17 +166,27 @@ As shown, `Rails::Command` displays the help output automatically if the `namesp
|
|||
is empty.
|
||||
|
||||
```ruby
|
||||
module Rails::Command
|
||||
class << self
|
||||
def invoke(namespace, args = [], **config)
|
||||
namespace = namespace.to_s
|
||||
namespace = "help" if namespace.blank? || HELP_MAPPINGS.include?(namespace)
|
||||
namespace = "version" if %w( -v --version ).include? namespace
|
||||
module Rails
|
||||
module Command
|
||||
class << self
|
||||
def invoke(full_namespace, args = [], **config)
|
||||
namespace = full_namespace = full_namespace.to_s
|
||||
|
||||
if command = find_by_namespace(namespace)
|
||||
command.perform(namespace, args, config)
|
||||
else
|
||||
find_by_namespace("rake").perform(namespace, args, config)
|
||||
if char = namespace =~ /:(\w+)$/
|
||||
command_name, namespace = $1, namespace.slice(0, char)
|
||||
else
|
||||
command_name = namespace
|
||||
end
|
||||
|
||||
command_name, namespace = "help", "help" if command_name.blank? || HELP_MAPPINGS.include?(command_name)
|
||||
command_name, namespace = "version", "version" if %w( -v --version ).include?(command_name)
|
||||
|
||||
command = find_by_namespace(namespace, command_name)
|
||||
if command && command.all_commands[command_name]
|
||||
command.perform(command_name, args, config)
|
||||
else
|
||||
find_by_namespace("rake").perform(full_namespace, args, config)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -190,14 +200,23 @@ module Rails
|
|||
module Command
|
||||
class ServerCommand < Base # :nodoc:
|
||||
def perform
|
||||
extract_environment_option_from_argument
|
||||
set_application_directory!
|
||||
prepare_restart
|
||||
|
||||
Rails::Server.new.tap do |server|
|
||||
Rails::Server.new(server_options).tap do |server|
|
||||
# Require application after server sets environment to propagate
|
||||
# the --environment option.
|
||||
require APP_PATH
|
||||
Dir.chdir(Rails.application.root)
|
||||
server.start
|
||||
|
||||
if server.serveable?
|
||||
print_boot_information(server.server, server.served_url)
|
||||
after_stop_callback = -> { say "Exiting" unless options[:daemon] }
|
||||
server.start(after_stop_callback)
|
||||
else
|
||||
say rack_server_suggestion(using)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -221,9 +240,14 @@ The `Rails::Server` class is defined in this file by inheriting from
|
|||
method in `rails/commands/server/server_command.rb`:
|
||||
|
||||
```ruby
|
||||
def initialize(*)
|
||||
super
|
||||
set_environment
|
||||
module Rails
|
||||
class Server < ::Rack::Server
|
||||
def initialize(options = nil)
|
||||
@default_options = options || {}
|
||||
super(@default_options)
|
||||
set_environment
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -233,97 +257,79 @@ Firstly, `super` is called which calls the `initialize` method on `Rack::Server`
|
|||
|
||||
`Rack::Server` is responsible for providing a common server interface for all Rack-based applications, which Rails is now a part of.
|
||||
|
||||
The `initialize` method in `Rack::Server` simply sets a couple of variables:
|
||||
The `initialize` method in `Rack::Server` simply sets several variables:
|
||||
|
||||
```ruby
|
||||
def initialize(options = nil)
|
||||
@options = options
|
||||
@app = options[:app] if options && options[:app]
|
||||
module Rack
|
||||
class Server
|
||||
def initialize(options = nil)
|
||||
@ignore_options = []
|
||||
|
||||
if options
|
||||
@use_default_options = false
|
||||
@options = options
|
||||
@app = options[:app] if options[:app]
|
||||
else
|
||||
argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
|
||||
@use_default_options = true
|
||||
@options = parse_options(argv)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
In this case, `options` will be `nil` so nothing happens in this method.
|
||||
In this case, return value of `Rails::Command::ServerCommand#server_options` will be assigned to `options`.
|
||||
When lines inside if statement is evaluated, a couple of instance variables will be set.
|
||||
|
||||
`server_options` method in `Rails::Command::ServerCommand` is defined as follows:
|
||||
|
||||
```ruby
|
||||
module Rails
|
||||
module Command
|
||||
class ServerCommand
|
||||
no_commands do
|
||||
def server_options
|
||||
{
|
||||
user_supplied_options: user_supplied_options,
|
||||
server: using,
|
||||
log_stdout: log_to_stdout?,
|
||||
Port: port,
|
||||
Host: host,
|
||||
DoNotReverseLookup: true,
|
||||
config: options[:config],
|
||||
environment: environment,
|
||||
daemonize: options[:daemon],
|
||||
pid: pid,
|
||||
caching: options[:dev_caching],
|
||||
restart_cmd: restart_command,
|
||||
early_hints: early_hints
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The value will be assigned to instance variable `@options`.
|
||||
|
||||
After `super` has finished in `Rack::Server`, we jump back to
|
||||
`rails/commands/server/server_command.rb`. At this point, `set_environment`
|
||||
is called within the context of the `Rails::Server` object and this method
|
||||
doesn't appear to do much at first glance:
|
||||
is called within the context of the `Rails::Server` object.
|
||||
|
||||
```ruby
|
||||
def set_environment
|
||||
ENV["RAILS_ENV"] ||= options[:environment]
|
||||
module Rails
|
||||
module Server
|
||||
def set_environment
|
||||
ENV["RAILS_ENV"] ||= options[:environment]
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
In fact, the `options` method here does quite a lot. This method is defined in `Rack::Server` like this:
|
||||
|
||||
```ruby
|
||||
def options
|
||||
@options ||= parse_options(ARGV)
|
||||
end
|
||||
```
|
||||
|
||||
Then `parse_options` is defined like this:
|
||||
|
||||
```ruby
|
||||
def parse_options(args)
|
||||
options = default_options
|
||||
|
||||
# Don't evaluate CGI ISINDEX parameters.
|
||||
# http://www.meb.uni-bonn.de/docs/cgi/cl.html
|
||||
args.clear if ENV.include?("REQUEST_METHOD")
|
||||
|
||||
options.merge! opt_parser.parse!(args)
|
||||
options[:config] = ::File.expand_path(options[:config])
|
||||
ENV["RACK_ENV"] = options[:environment]
|
||||
options
|
||||
end
|
||||
```
|
||||
|
||||
With the `default_options` set to this:
|
||||
|
||||
```ruby
|
||||
def default_options
|
||||
super.merge(
|
||||
Port: ENV.fetch("PORT", 3000).to_i,
|
||||
Host: ENV.fetch("HOST", "localhost").dup,
|
||||
DoNotReverseLookup: true,
|
||||
environment: (ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development").dup,
|
||||
daemonize: false,
|
||||
caching: nil,
|
||||
pid: ENV.fetch("PIDFILE", Options::DEFAULT_PIDFILE).dup,
|
||||
restart_cmd: restart_command)
|
||||
end
|
||||
```
|
||||
|
||||
There is no `REQUEST_METHOD` key in `ENV` so we can skip over that line. The next line merges in the options from `opt_parser` which is defined plainly in `Rack::Server`:
|
||||
|
||||
```ruby
|
||||
def opt_parser
|
||||
Options.new
|
||||
end
|
||||
```
|
||||
|
||||
The class **is** defined in `Rack::Server`, but is overwritten in
|
||||
`Rails::Server` to take different arguments. Its `parse!` method looks
|
||||
like this:
|
||||
|
||||
```ruby
|
||||
def parse!(args)
|
||||
args, options = args.dup, {}
|
||||
|
||||
option_parser(options).parse! args
|
||||
|
||||
options[:log_stdout] = options[:daemonize].blank? && (options[:environment] || Rails.env) == "development"
|
||||
options[:server] = args.shift
|
||||
options
|
||||
end
|
||||
```
|
||||
|
||||
This method will set up keys for the `options` which Rails will then be
|
||||
able to use to determine how its server should run. After `initialize`
|
||||
has finished, we jump back into the server command where `APP_PATH` (which was
|
||||
set earlier) is required.
|
||||
After `initialize` has finished, we jump back into the server command
|
||||
where `APP_PATH` (which was set earlier) is required.
|
||||
|
||||
### `config/application`
|
||||
|
||||
|
@ -337,92 +343,103 @@ After `config/application` is loaded, `server.start` is called. This method is
|
|||
defined like this:
|
||||
|
||||
```ruby
|
||||
def start
|
||||
trap(:INT) { exit }
|
||||
create_tmp_directories
|
||||
setup_dev_caching
|
||||
log_to_stdout if options[:log_stdout]
|
||||
module Rails
|
||||
class Server < ::Rack::Server
|
||||
def start(after_stop_callback = nil)
|
||||
trap(:INT) { exit }
|
||||
create_tmp_directories
|
||||
setup_dev_caching
|
||||
log_to_stdout if options[:log_stdout]
|
||||
|
||||
super
|
||||
...
|
||||
super()
|
||||
...
|
||||
>>>>>>> c5102225a36d254dc067c6d5a606856233d46e99
|
||||
end
|
||||
|
||||
private
|
||||
def setup_dev_caching
|
||||
if options[:environment] == "development"
|
||||
Rails::DevCaching.enable_by_argument(options[:caching])
|
||||
end
|
||||
end
|
||||
|
||||
def create_tmp_directories
|
||||
%w(cache pids sockets).each do |dir_to_make|
|
||||
FileUtils.mkdir_p(File.join(Rails.root, "tmp", dir_to_make))
|
||||
end
|
||||
end
|
||||
|
||||
def log_to_stdout
|
||||
wrapped_app # touch the app so the logger is set up
|
||||
|
||||
console = ActiveSupport::Logger.new(STDOUT)
|
||||
console.formatter = Rails.logger.formatter
|
||||
console.level = Rails.logger.level
|
||||
|
||||
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
|
||||
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def setup_dev_caching
|
||||
if options[:environment] == "development"
|
||||
Rails::DevCaching.enable_by_argument(options[:caching])
|
||||
end
|
||||
end
|
||||
|
||||
def create_tmp_directories
|
||||
%w(cache pids sockets).each do |dir_to_make|
|
||||
FileUtils.mkdir_p(File.join(Rails.root, 'tmp', dir_to_make))
|
||||
end
|
||||
end
|
||||
|
||||
def log_to_stdout
|
||||
wrapped_app # touch the app so the logger is set up
|
||||
|
||||
console = ActiveSupport::Logger.new(STDOUT)
|
||||
console.formatter = Rails.logger.formatter
|
||||
console.level = Rails.logger.level
|
||||
|
||||
unless ActiveSupport::Logger.logger_outputs_to?(Rails.logger, STDOUT)
|
||||
Rails.logger.extend(ActiveSupport::Logger.broadcast(console))
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
This is where the first output of the Rails initialization happens. This method
|
||||
creates a trap for `INT` signals, so if you `CTRL-C` the server, it will exit the
|
||||
process. As we can see from the code here, it will create the `tmp/cache`,
|
||||
This method creates a trap for `INT` signals, so if you `CTRL-C` the server, it will exit the process.
|
||||
As we can see from the code here, it will create the `tmp/cache`,
|
||||
`tmp/pids`, and `tmp/sockets` directories. It then enables caching in development
|
||||
if `rails server` is called with `--dev-caching`. Finally, it calls `wrapped_app` which is
|
||||
responsible for creating the Rack app, before creating and assigning an instance
|
||||
of `ActiveSupport::Logger`.
|
||||
|
||||
The `super` method will call `Rack::Server.start` which begins its definition like this:
|
||||
The `super` method will call `Rack::Server.start` which begins its definition as follows:
|
||||
|
||||
```ruby
|
||||
def start &blk
|
||||
if options[:warn]
|
||||
$-w = true
|
||||
end
|
||||
module Rack
|
||||
class Server
|
||||
def start &blk
|
||||
if options[:warn]
|
||||
$-w = true
|
||||
end
|
||||
|
||||
if includes = options[:include]
|
||||
$LOAD_PATH.unshift(*includes)
|
||||
end
|
||||
if includes = options[:include]
|
||||
$LOAD_PATH.unshift(*includes)
|
||||
end
|
||||
|
||||
if library = options[:require]
|
||||
require library
|
||||
end
|
||||
if library = options[:require]
|
||||
require library
|
||||
end
|
||||
|
||||
if options[:debug]
|
||||
$DEBUG = true
|
||||
p options[:server]
|
||||
pp wrapped_app
|
||||
pp app
|
||||
end
|
||||
if options[:debug]
|
||||
$DEBUG = true
|
||||
require 'pp'
|
||||
p options[:server]
|
||||
pp wrapped_app
|
||||
pp app
|
||||
end
|
||||
|
||||
check_pid! if options[:pid]
|
||||
check_pid! if options[:pid]
|
||||
|
||||
# Touch the wrapped app, so that the config.ru is loaded before
|
||||
# daemonization (i.e. before chdir, etc).
|
||||
wrapped_app
|
||||
# Touch the wrapped app, so that the config.ru is loaded before
|
||||
# daemonization (i.e. before chdir, etc).
|
||||
handle_profiling(options[:heapfile], options[:profile_mode], options[:profile_file]) do
|
||||
wrapped_app
|
||||
end
|
||||
|
||||
daemonize_app if options[:daemonize]
|
||||
daemonize_app if options[:daemonize]
|
||||
|
||||
write_pid if options[:pid]
|
||||
write_pid if options[:pid]
|
||||
|
||||
trap(:INT) do
|
||||
if server.respond_to?(:shutdown)
|
||||
server.shutdown
|
||||
else
|
||||
exit
|
||||
trap(:INT) do
|
||||
if server.respond_to?(:shutdown)
|
||||
server.shutdown
|
||||
else
|
||||
exit
|
||||
end
|
||||
end
|
||||
|
||||
server.run wrapped_app, options, &blk
|
||||
end
|
||||
end
|
||||
|
||||
server.run wrapped_app, options, &blk
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -431,30 +448,42 @@ we're going to explore more (even though it was executed before, and
|
|||
thus memoized by now).
|
||||
|
||||
```ruby
|
||||
@wrapped_app ||= build_app app
|
||||
module Rack
|
||||
class Server
|
||||
def wrapped_app
|
||||
@wrapped_app ||= build_app app
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The `app` method here is defined like so:
|
||||
|
||||
```ruby
|
||||
def app
|
||||
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
||||
end
|
||||
...
|
||||
private
|
||||
def build_app_and_options_from_config
|
||||
if !::File.exist? options[:config]
|
||||
abort "configuration #{options[:config]} not found"
|
||||
module Rack
|
||||
class Server
|
||||
def app
|
||||
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
||||
end
|
||||
...
|
||||
|
||||
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
||||
self.options.merge! options
|
||||
app
|
||||
end
|
||||
private
|
||||
def build_app_and_options_from_config
|
||||
if !::File.exist? options[:config]
|
||||
abort "configuration #{options[:config]} not found"
|
||||
end
|
||||
|
||||
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
||||
@options.merge!(options) { |key, old, new| old }
|
||||
app
|
||||
end
|
||||
|
||||
def build_app_from_string
|
||||
Rack::Builder.new_from_string(self.options[:builder])
|
||||
end
|
||||
|
||||
def build_app_from_string
|
||||
Rack::Builder.new_from_string(self.options[:builder])
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The `options[:config]` value defaults to `config.ru` which contains this:
|
||||
|
@ -463,24 +492,35 @@ The `options[:config]` value defaults to `config.ru` which contains this:
|
|||
# This file is used by Rack-based servers to start the application.
|
||||
|
||||
require_relative 'config/environment'
|
||||
run <%= app_const %>
|
||||
|
||||
run Rails.application
|
||||
```
|
||||
|
||||
|
||||
The `Rack::Builder.parse_file` method here takes the content from this `config.ru` file and parses it using this code:
|
||||
|
||||
```ruby
|
||||
app = new_from_string cfgfile, config
|
||||
module Rack
|
||||
class Builder
|
||||
def self.load_file(path, opts = Server::Options.new)
|
||||
...
|
||||
app = new_from_string cfgfile, config
|
||||
...
|
||||
end
|
||||
|
||||
...
|
||||
...
|
||||
|
||||
def self.new_from_string(builder_script, file="(rackup)")
|
||||
eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
|
||||
TOPLEVEL_BINDING, file, 0
|
||||
def self.new_from_string(builder_script, file="(rackup)")
|
||||
eval "Rack::Builder.new {\n" + builder_script + "\n}.to_app",
|
||||
TOPLEVEL_BINDING, file, 0
|
||||
end
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`. This is where the majority of the initialization process of Rails happens. The `require` line for `config/environment.rb` in `config.ru` is the first to run:
|
||||
The `initialize` method of `Rack::Builder` will take the block here and execute it within an instance of `Rack::Builder`.
|
||||
This is where the majority of the initialization process of Rails happens.
|
||||
The `require` line for `config/environment.rb` in `config.ru` is the first to run:
|
||||
|
||||
```ruby
|
||||
require_relative 'config/environment'
|
||||
|
@ -567,7 +607,7 @@ defined in `rails/application.rb`.
|
|||
The `initialize!` method looks like this:
|
||||
|
||||
```ruby
|
||||
def initialize!(group=:default) #:nodoc:
|
||||
def initialize!(group = :default) #:nodoc:
|
||||
raise "Application has been already initialized." if @initialized
|
||||
run_initializers(group, self)
|
||||
@initialized = true
|
||||
|
@ -579,7 +619,7 @@ As you can see, you can only initialize an app once. The initializers are run th
|
|||
the `run_initializers` method which is defined in `railties/lib/rails/initializable.rb`:
|
||||
|
||||
```ruby
|
||||
def run_initializers(group=:default, *args)
|
||||
def run_initializers(group = :default, *args)
|
||||
return if instance_variable_defined?(:@ran)
|
||||
initializers.tsort_each do |initializer|
|
||||
initializer.run(*args) if initializer.belongs_to?(group)
|
||||
|
@ -608,42 +648,53 @@ After this is done we go back to `Rack::Server`.
|
|||
Last time we left when the `app` method was being defined:
|
||||
|
||||
```ruby
|
||||
def app
|
||||
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
||||
end
|
||||
...
|
||||
private
|
||||
def build_app_and_options_from_config
|
||||
if !::File.exist? options[:config]
|
||||
abort "configuration #{options[:config]} not found"
|
||||
module Rack
|
||||
class Server
|
||||
def app
|
||||
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
|
||||
end
|
||||
...
|
||||
|
||||
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
||||
self.options.merge! options
|
||||
app
|
||||
end
|
||||
private
|
||||
def build_app_and_options_from_config
|
||||
if !::File.exist? options[:config]
|
||||
abort "configuration #{options[:config]} not found"
|
||||
end
|
||||
|
||||
app, options = Rack::Builder.parse_file(self.options[:config], opt_parser)
|
||||
@options.merge!(options) { |key, old, new| old }
|
||||
app
|
||||
end
|
||||
|
||||
def build_app_from_string
|
||||
Rack::Builder.new_from_string(self.options[:builder])
|
||||
end
|
||||
|
||||
def build_app_from_string
|
||||
Rack::Builder.new_from_string(self.options[:builder])
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
At this point `app` is the Rails app itself (a middleware), and what
|
||||
happens next is Rack will call all the provided middlewares:
|
||||
|
||||
```ruby
|
||||
def build_app(app)
|
||||
middleware[options[:environment]].reverse_each do |middleware|
|
||||
middleware = middleware.call(self) if middleware.respond_to?(:call)
|
||||
next unless middleware
|
||||
klass = middleware.shift
|
||||
app = klass.new(app, *middleware)
|
||||
module Rack
|
||||
class Server
|
||||
private
|
||||
def build_app(app)
|
||||
middleware[options[:environment]].reverse_each do |middleware|
|
||||
middleware = middleware.call(self) if middleware.respond_to?(:call)
|
||||
next unless middleware
|
||||
klass, *args = middleware
|
||||
app = klass.new(app, *args)
|
||||
end
|
||||
app
|
||||
end
|
||||
end
|
||||
app
|
||||
end
|
||||
```
|
||||
|
||||
Remember, `build_app` was called (by `wrapped_app`) in the last line of `Server#start`.
|
||||
Remember, `build_app` was called (by `wrapped_app`) in the last line of `Rack::Server#start`.
|
||||
Here's how it looked like when we left:
|
||||
|
||||
```ruby
|
||||
|
@ -655,46 +706,29 @@ server you're using. For example, if you were using Puma, here's what
|
|||
the `run` method would look like:
|
||||
|
||||
```ruby
|
||||
...
|
||||
DEFAULT_OPTIONS = {
|
||||
:Host => '0.0.0.0',
|
||||
:Port => 8080,
|
||||
:Threads => '0:16',
|
||||
:Verbose => false
|
||||
}
|
||||
module Rack
|
||||
module Handler
|
||||
module Puma
|
||||
...
|
||||
def self.run(app, options = {})
|
||||
conf = self.config(app, options)
|
||||
|
||||
def self.run(app, options = {})
|
||||
options = DEFAULT_OPTIONS.merge(options)
|
||||
events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio
|
||||
|
||||
if options[:Verbose]
|
||||
app = Rack::CommonLogger.new(app, STDOUT)
|
||||
launcher = ::Puma::Launcher.new(conf, :events => events)
|
||||
|
||||
yield launcher if block_given?
|
||||
begin
|
||||
launcher.run
|
||||
rescue Interrupt
|
||||
puts "* Gracefully stopping, waiting for requests to finish"
|
||||
launcher.stop
|
||||
puts "* Goodbye!"
|
||||
end
|
||||
end
|
||||
...
|
||||
end
|
||||
end
|
||||
|
||||
if options[:environment]
|
||||
ENV['RACK_ENV'] = options[:environment].to_s
|
||||
end
|
||||
|
||||
server = ::Puma::Server.new(app)
|
||||
min, max = options[:Threads].split(':', 2)
|
||||
|
||||
puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
|
||||
puts "* Min threads: #{min}, max threads: #{max}"
|
||||
puts "* Environment: #{ENV['RACK_ENV']}"
|
||||
puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
|
||||
|
||||
server.add_tcp_listener options[:Host], options[:Port]
|
||||
server.min_threads = min
|
||||
server.max_threads = max
|
||||
yield server if block_given?
|
||||
|
||||
begin
|
||||
server.run.join
|
||||
rescue Interrupt
|
||||
puts "* Gracefully stopping, waiting for requests to finish"
|
||||
server.stop(true)
|
||||
puts "* Goodbye!"
|
||||
end
|
||||
|
||||
end
|
||||
```
|
||||
|
||||
|
|
Loading…
Reference in a new issue