yarn 0.0.1 → 0.0.2
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.
- data/.gitignore +1 -0
- data/Gemfile +0 -3
- data/README.md +25 -1
- data/bin/yarn +6 -4
- data/features/concurrency.feature +4 -4
- data/features/dynamic_request.feature +6 -1
- data/features/rack.feature +5 -8
- data/features/static_request.feature +2 -2
- data/features/step_definitions/rack_steps.rb +13 -0
- data/features/step_definitions/server_steps.rb +5 -5
- data/features/step_definitions/web_steps.rb +8 -0
- data/lib/rack/handler/yarn.rb +4 -3
- data/lib/yarn/error_page.rb +2 -1
- data/lib/yarn/logging.rb +1 -1
- data/lib/yarn/parslet_parser.rb +9 -24
- data/lib/yarn/rack_handler.rb +11 -9
- data/lib/yarn/request_handler.rb +21 -12
- data/lib/yarn/server.rb +39 -30
- data/lib/yarn/version.rb +1 -1
- data/spec/helpers.rb +16 -8
- data/spec/rack/handler/yarn_spec.rb +21 -0
- data/spec/spec_helper.rb +1 -4
- data/spec/yarn/directory_lister_spec.rb +0 -5
- data/spec/yarn/logging_spec.rb +3 -2
- data/spec/yarn/parslet_parser_spec.rb +26 -0
- data/spec/yarn/rack_handler_spec.rb +15 -4
- data/spec/yarn/request_handler_spec.rb +17 -7
- data/spec/yarn/server_spec.rb +49 -8
- data/test_objects/.gitignore +1 -0
- data/test_objects/app.rb +0 -2
- data/test_objects/config.ru +1 -49
- data/test_objects/rails_test/.gitignore +5 -0
- data/test_objects/rails_test/Gemfile +34 -0
- data/test_objects/rails_test/README +261 -0
- data/test_objects/rails_test/Rakefile +7 -0
- data/test_objects/rails_test/app/assets/images/rails.png +0 -0
- data/test_objects/rails_test/app/assets/javascripts/application.js +6 -0
- data/test_objects/rails_test/app/assets/stylesheets/application.css +7 -0
- data/test_objects/rails_test/app/assets/stylesheets/scaffolds.css.scss +56 -0
- data/test_objects/rails_test/app/mailers/.gitkeep +0 -0
- data/test_objects/rails_test/app/models/.gitkeep +0 -0
- data/test_objects/rails_test/app/views/layouts/application.html.erb +15 -0
- data/test_objects/rails_test/app/views/posts/_form.html.erb +25 -0
- data/test_objects/rails_test/app/views/posts/edit.html.erb +6 -0
- data/test_objects/rails_test/app/views/posts/index.html.erb +20 -0
- data/test_objects/rails_test/app/views/posts/new.html.erb +5 -0
- data/test_objects/rails_test/app/views/posts/show.html.erb +15 -0
- data/test_objects/rails_test/config.ru +4 -0
- data/test_objects/rails_test/config/database.yml +25 -0
- data/test_objects/rails_test/config/locales/en.yml +5 -0
- data/test_objects/rails_test/doc/README_FOR_APP +2 -0
- data/test_objects/rails_test/lib/assets/.gitkeep +0 -0
- data/test_objects/rails_test/lib/tasks/.gitkeep +0 -0
- data/test_objects/rails_test/log/.gitkeep +0 -0
- data/test_objects/rails_test/public/404.html +26 -0
- data/test_objects/rails_test/public/422.html +26 -0
- data/test_objects/rails_test/public/500.html +26 -0
- data/test_objects/rails_test/public/favicon.ico +0 -0
- data/test_objects/rails_test/public/robots.txt +5 -0
- data/test_objects/rails_test/script/rails +6 -0
- data/test_objects/rails_test/test/fixtures/.gitkeep +0 -0
- data/test_objects/rails_test/test/fixtures/posts.yml +9 -0
- data/test_objects/rails_test/test/functional/.gitkeep +0 -0
- data/test_objects/rails_test/test/integration/.gitkeep +0 -0
- data/test_objects/rails_test/test/unit/.gitkeep +0 -0
- data/test_objects/rails_test/vendor/assets/stylesheets/.gitkeep +0 -0
- data/test_objects/rails_test/vendor/plugins/.gitkeep +0 -0
- data/yarn.gemspec +4 -8
- metadata +59 -59
- data/lib/yarn/worker.rb +0 -19
- data/lib/yarn/worker_pool.rb +0 -36
- data/spec/yarn/worker_pool_spec.rb +0 -23
- data/spec/yarn/worker_spec.rb +0 -26
- data/test_objects/simple_rack.rb +0 -12
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
1
|
# Yarn #
|
2
2
|
|
3
|
-
|
3
|
+
Yarn is a multi-threaded webserver written in Ruby 1.9 by Jesper Kjeldgaard.
|
4
|
+
It handles concurrent requests by means of a set of workers and a job queue for incomming requests.
|
5
|
+
|
6
|
+
Supports:
|
7
|
+
*
|
8
|
+
|
9
|
+
|
10
|
+
## Installation ##
|
11
|
+
`gem install yarn`
|
12
|
+
|
13
|
+
|
14
|
+
## Usage ##
|
15
|
+
To use Yarn with Rack applications:
|
16
|
+
|
17
|
+
`rackup -s Yarn <rackup file (config.ru)>`
|
18
|
+
|
19
|
+
|
20
|
+
To use Yarn for serving static and ruby (*.rb) files:
|
21
|
+
|
22
|
+
|
23
|
+
yarn [options]
|
24
|
+
where [options] are:
|
25
|
+
--host, -h <s>: Hostname or IP address of the server (default: 127.0.0.1)
|
26
|
+
--port, -p <i>: Port number to listen on for incomming requests (default: 3000)
|
27
|
+
--workers, -w <s>: Number of worker threads (default: 32)
|
data/bin/yarn
CHANGED
@@ -7,9 +7,9 @@ require 'trollop'
|
|
7
7
|
require 'yarn'
|
8
8
|
|
9
9
|
opts = Trollop::options do
|
10
|
-
version "Yarn v
|
10
|
+
version "Yarn v#{Yarn::VERSION} 2011 Jesper Kjeldgaard"
|
11
11
|
banner <<-EOS
|
12
|
-
Yarn v
|
12
|
+
Yarn v#{Yarn::VERSION} is a multiprocess webserver written in Ruby 1.9.2
|
13
13
|
|
14
14
|
Usage: yarn [options]
|
15
15
|
where [options] are:
|
@@ -17,8 +17,10 @@ EOS
|
|
17
17
|
|
18
18
|
opt :host, "Hostname or IP address of the server", :default => "127.0.0.1"
|
19
19
|
opt :port, "Port number to listen on for incomming requests", :default => 3000
|
20
|
-
opt :
|
20
|
+
opt :workers, "Number of worker threads", :default => 4
|
21
|
+
opt :rack, "Rackup file <config.ru>", :default => "off"
|
22
|
+
opt :debug, "Output debug messages"
|
21
23
|
end
|
22
24
|
|
23
|
-
server = Yarn::Server.new(
|
25
|
+
server = Yarn::Server.new(opts)
|
24
26
|
server.start
|
@@ -2,14 +2,14 @@ Feature: Concurrency
|
|
2
2
|
|
3
3
|
As a developer
|
4
4
|
I want to be able to serve multiple requests in parallel
|
5
|
-
To increase server
|
5
|
+
To increase server performance
|
6
6
|
|
7
7
|
Background:
|
8
|
-
Given the server is running
|
8
|
+
Given the server is running
|
9
9
|
|
10
10
|
Scenario: Perform two requests in parallel
|
11
11
|
Given a client "A"
|
12
12
|
And a client "B"
|
13
|
-
When client "A" makes a "
|
14
|
-
And client "B" makes a "1" second request
|
13
|
+
When client "A" makes a "1" seconds request
|
14
|
+
And client "B" makes a "0.1" second request
|
15
15
|
Then client "B" receives a response before client "A"
|
@@ -5,9 +5,14 @@ Feature: Dynamic request
|
|
5
5
|
In order to provide dynamic content
|
6
6
|
|
7
7
|
Background:
|
8
|
-
Given the server is running
|
8
|
+
Given the server is running
|
9
9
|
|
10
10
|
Scenario: Serve a dynamic Ruby file
|
11
11
|
Given the file "/app.rb" exist
|
12
12
|
When I go to "/app.rb"
|
13
13
|
Then the response should contain "Dynamic request complete"
|
14
|
+
|
15
|
+
Scenario: Support POST data
|
16
|
+
Given the file "/post_app.rb" exist
|
17
|
+
When I post "field1" as "value1" to "/test_objects/post_app.rb"
|
18
|
+
Then the response should be "Recieved field1=value1"
|
data/features/rack.feature
CHANGED
@@ -4,15 +4,12 @@ Feature: Implement rack interface
|
|
4
4
|
I want to have a rack handler
|
5
5
|
In order to serve rack applications
|
6
6
|
|
7
|
-
@wip
|
8
7
|
Scenario: Serve a one-file rack application
|
9
|
-
Given
|
10
|
-
And the server is running as "rack"
|
8
|
+
Given the rack test app is running
|
11
9
|
When I go to "/"
|
12
|
-
Then the response should contain "
|
10
|
+
Then the response should contain "Rack works"
|
13
11
|
|
14
12
|
Scenario: Serve a rails application
|
15
|
-
Given
|
16
|
-
|
17
|
-
|
18
|
-
Then the response should contain "Rack rails works"
|
13
|
+
Given the rails test app is running
|
14
|
+
When I go to ""
|
15
|
+
Then the response should contain "Yarn Test Blog"
|
@@ -5,7 +5,7 @@ Feature: Static file requests
|
|
5
5
|
To provide fast content on the Internet
|
6
6
|
|
7
7
|
Background:
|
8
|
-
Given the server is running
|
8
|
+
Given the server is running
|
9
9
|
|
10
10
|
Scenario: Serve a static html file
|
11
11
|
Given the file "index.html" exist
|
@@ -22,4 +22,4 @@ Feature: Static file requests
|
|
22
22
|
Given the file "non-existent-file.html" does not exist
|
23
23
|
When I go to "non-existent-file.html"
|
24
24
|
Then the response should contain "404"
|
25
|
-
Then the response should contain "
|
25
|
+
Then the response should contain "does not exist"
|
@@ -1,3 +1,16 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
1
3
|
Given /^I have a rack application "([^"]*)"$/ do |app|
|
2
4
|
testfile_exists?(app).should be_true
|
3
5
|
end
|
6
|
+
|
7
|
+
Given /^the rack test app is running$/ do
|
8
|
+
start_server(3000,"test_objects/config.ru")
|
9
|
+
end
|
10
|
+
|
11
|
+
Given /^the rails test app is running$/ do
|
12
|
+
current_dir = Dir.pwd
|
13
|
+
Dir.chdir("test_objects/rails_test")
|
14
|
+
start_server(3000,"config.ru")
|
15
|
+
Dir.chdir(current_dir)
|
16
|
+
end
|
@@ -9,11 +9,7 @@ When /^I stop the server$/ do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
Given /^the server is running$/ do
|
12
|
-
start_server
|
13
|
-
end
|
14
|
-
|
15
|
-
Given /^the server is running as "([^"]*)"$/ do |handler_type|
|
16
|
-
start_server(3000, handler_type.to_sym)
|
12
|
+
start_server(3000)
|
17
13
|
end
|
18
14
|
|
19
15
|
Given /^the server is not running$/ do
|
@@ -40,3 +36,7 @@ end
|
|
40
36
|
Then /^I should see "([^"]*)"$/ do |message|
|
41
37
|
$console.contains? message
|
42
38
|
end
|
39
|
+
|
40
|
+
Then /^Pry$/ do
|
41
|
+
binding.pry
|
42
|
+
end
|
@@ -5,3 +5,11 @@ end
|
|
5
5
|
Then /^the response should contain "([^"]*)"$/ do |content|
|
6
6
|
@response.body.should include(content)
|
7
7
|
end
|
8
|
+
|
9
|
+
Then /^the response should be "([^"]*)"$/ do |content|
|
10
|
+
@response.body.gsub(/\n?/,"").should == content
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I post "([^"]*)" as "([^"]*)" to "([^"]*)"$/ do |key, value, url|
|
14
|
+
@response = post(url, { key.to_sym => value })
|
15
|
+
end
|
data/lib/rack/handler/yarn.rb
CHANGED
@@ -6,14 +6,15 @@ module Rack
|
|
6
6
|
module Handler
|
7
7
|
class Yarn
|
8
8
|
def self.run(app, options={})
|
9
|
-
|
10
|
-
server.
|
9
|
+
options = options.merge({ rack: app })
|
10
|
+
@server = ::Yarn::Server.new(options)
|
11
|
+
@server.start
|
11
12
|
end
|
12
13
|
|
13
14
|
def self.valid_options
|
14
15
|
{
|
15
16
|
"Host=HOST" => "Hostname to listen on (default: 127.0.0.1)",
|
16
|
-
"Port=PORT" => "Port to listen on (default: 3000)"
|
17
|
+
"Port=PORT" => "Port to listen on (default: 3000)"
|
17
18
|
}
|
18
19
|
end
|
19
20
|
end
|
data/lib/yarn/error_page.rb
CHANGED
@@ -4,7 +4,8 @@ module Yarn
|
|
4
4
|
|
5
5
|
def serve_404_page
|
6
6
|
@response.status = 404
|
7
|
-
|
7
|
+
fn = @request[:uri][:path] if @request
|
8
|
+
@response.body = ["<html><head><title>404</title></head><body><h1>File #{fn} does not exist.</h1></body><html>"]
|
8
9
|
end
|
9
10
|
|
10
11
|
def serve_500_page
|
data/lib/yarn/logging.rb
CHANGED
data/lib/yarn/parslet_parser.rb
CHANGED
@@ -15,7 +15,6 @@ module Yarn
|
|
15
15
|
rule(:spaces) { match('\s+') }
|
16
16
|
|
17
17
|
# header rules
|
18
|
-
|
19
18
|
rule(:header_value) { match['^\r\n'].once }
|
20
19
|
|
21
20
|
rule(:header_name) { match['a-zA-Z\-'].once }
|
@@ -27,28 +26,18 @@ module Yarn
|
|
27
26
|
header_value.as(:value).maybe >>
|
28
27
|
crlf.maybe
|
29
28
|
end
|
30
|
-
|
31
|
-
# request-line rules
|
32
29
|
|
30
|
+
# request-line rules
|
33
31
|
rule(:http_version) { match['HTTP\/\d\.\d'].once }
|
34
32
|
|
35
|
-
rule(:param_value) { match['^&\s+'].once }
|
36
|
-
|
37
|
-
rule(:param_name) { match['^=+'].once }
|
38
|
-
|
39
|
-
rule(:param) do
|
40
|
-
param_name.as(:name) >>
|
41
|
-
str("=") >>
|
42
|
-
param_value.as(:value) >>
|
43
|
-
str("&").maybe
|
44
|
-
end
|
45
|
-
|
46
33
|
rule(:query) do
|
47
34
|
match['\S+'].repeat(1)
|
48
35
|
end
|
49
36
|
|
50
37
|
rule(:path) do
|
51
|
-
match['^\?'].repeat(1).as(:path) >>
|
38
|
+
match['^\?'].repeat(1).as(:path) >>
|
39
|
+
str("?") >>
|
40
|
+
query.as(:query) | match['^\s'].once.as(:path)
|
52
41
|
end
|
53
42
|
|
54
43
|
rule(:port) { match['\d+'].repeat(1) }
|
@@ -78,11 +67,16 @@ module Yarn
|
|
78
67
|
http_version.as(:version) >>
|
79
68
|
crlf.maybe
|
80
69
|
end
|
70
|
+
|
71
|
+
# body rule
|
72
|
+
rule(:body) { match['\S'].once }
|
81
73
|
|
82
74
|
# RFC2616: Request-Line *(( header ) CRLF) CRLF [ message-body ]
|
83
75
|
rule(:request) do
|
84
76
|
request_line >>
|
85
77
|
header.repeat.as(:_process_headers).as(:headers) >>
|
78
|
+
crlf.maybe >>
|
79
|
+
body.as(:body).maybe >>
|
86
80
|
crlf.maybe
|
87
81
|
end
|
88
82
|
|
@@ -91,19 +85,10 @@ module Yarn
|
|
91
85
|
|
92
86
|
def run(input)
|
93
87
|
tree = parse input
|
94
|
-
tree = ParamsTransformer.new.apply tree
|
95
88
|
HeadersTransformer.new.apply tree
|
96
89
|
end
|
97
90
|
end
|
98
91
|
|
99
|
-
class ParamsTransformer < Parslet::Transform
|
100
|
-
rule(:_process_params => subtree(:params)) do
|
101
|
-
hash = {}
|
102
|
-
params.each { |h| hash[h[:name].to_s] = h[:value] }
|
103
|
-
hash
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
92
|
class HeadersTransformer < Parslet::Transform
|
108
93
|
rule(:_process_headers => subtree(:headers)) do
|
109
94
|
hash = {}
|
data/lib/yarn/rack_handler.rb
CHANGED
@@ -4,16 +4,18 @@ require 'pry'
|
|
4
4
|
module Yarn
|
5
5
|
class RackHandler < RequestHandler
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
attr_accessor :env
|
8
|
+
|
9
|
+
def initialize(app)
|
10
|
+
@parser = ParsletParser.new
|
11
|
+
@response = Response.new
|
10
12
|
@app = app
|
11
13
|
end
|
12
14
|
|
13
15
|
def prepare_response
|
14
16
|
begin
|
15
|
-
|
16
|
-
@response.content = @app.call(env)
|
17
|
+
make_env
|
18
|
+
@response.content = @app.call(@env)
|
17
19
|
rescue Exception => e
|
18
20
|
log e.message
|
19
21
|
log e.backtrace
|
@@ -21,18 +23,18 @@ module Yarn
|
|
21
23
|
end
|
22
24
|
|
23
25
|
def make_env
|
24
|
-
env = {
|
26
|
+
@env = {
|
25
27
|
"REQUEST_METHOD" => @request[:method].to_s,
|
26
28
|
"PATH_INFO" => @request[:uri][:path].to_s,
|
27
29
|
"QUERY_STRING" => @request[:uri][:query].to_s,
|
28
|
-
"SERVER_NAME" => @
|
29
|
-
"SERVER_PORT" => @
|
30
|
+
"SERVER_NAME" => @request[:uri][:host].to_s,
|
31
|
+
"SERVER_PORT" => @request[:uri][:port].to_s,
|
30
32
|
"SCRIPT_NAME" => "",
|
31
33
|
"rack.input" => StringIO.new("").set_encoding(Encoding::ASCII_8BIT),
|
32
34
|
"rack.version" => Rack::VERSION,
|
33
35
|
"rack.errors" => $output,
|
34
36
|
"rack.multithread" => true,
|
35
|
-
"rack.multiprocess" =>
|
37
|
+
"rack.multiprocess" => true,
|
36
38
|
"rack.run_once" => false,
|
37
39
|
"rack.url_scheme" => "http"
|
38
40
|
}
|
data/lib/yarn/request_handler.rb
CHANGED
@@ -14,24 +14,26 @@ module Yarn
|
|
14
14
|
|
15
15
|
attr_accessor :session, :parser, :request, :response
|
16
16
|
|
17
|
-
def initialize
|
17
|
+
def initialize
|
18
18
|
@parser = ParsletParser.new
|
19
19
|
@response = Response.new
|
20
20
|
end
|
21
21
|
|
22
22
|
def run(session)
|
23
|
-
@response = Response.new
|
24
23
|
set_common_headers
|
25
24
|
@session = session
|
26
25
|
begin
|
27
26
|
parse_request
|
27
|
+
debug "Request parsed, path: #{request_path}"
|
28
28
|
prepare_response
|
29
|
+
debug "Response prepared: #{@response.status}"
|
29
30
|
return_response
|
30
|
-
log "
|
31
|
+
log "#{STATUS_CODES[@response.status]} #{client_address} #{request_path}"
|
31
32
|
rescue EmptyRequestError
|
32
33
|
log "Empty request from #{client_address}"
|
33
34
|
ensure
|
34
35
|
close_connection
|
36
|
+
debug "Connection closed"
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
@@ -72,7 +74,7 @@ module Yarn
|
|
72
74
|
end
|
73
75
|
|
74
76
|
def execute_script(path)
|
75
|
-
response = `ruby #{path}`
|
77
|
+
response = `ruby #{path} #{post_body}`
|
76
78
|
if !! ($?.to_s =~ /1$/)
|
77
79
|
raise ProcessingError
|
78
80
|
else
|
@@ -80,6 +82,10 @@ module Yarn
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
85
|
+
def post_body
|
86
|
+
@request ? @request[:body].to_s : ""
|
87
|
+
end
|
88
|
+
|
83
89
|
def return_response
|
84
90
|
@session.puts "HTTP/1.1 #{@response.status} #{STATUS_CODES[@response.status]}"
|
85
91
|
@session.puts @response.headers.map { |k,v| "#{k}: #{v}" }
|
@@ -101,9 +107,17 @@ module Yarn
|
|
101
107
|
def read_request
|
102
108
|
input = []
|
103
109
|
while (line = @session.gets) do
|
104
|
-
|
105
|
-
|
110
|
+
length = line.gsub(/\D/,"") if line =~ /Content-Length/
|
111
|
+
if line == "\r\n"
|
112
|
+
input << line
|
113
|
+
input << @session.read(length.to_i) if length
|
114
|
+
break
|
115
|
+
else
|
116
|
+
input << line
|
117
|
+
end
|
106
118
|
end
|
119
|
+
@session.close_read
|
120
|
+
debug "Done reading request"
|
107
121
|
input.join
|
108
122
|
end
|
109
123
|
|
@@ -141,12 +155,7 @@ module Yarn
|
|
141
155
|
|
142
156
|
def read_file(path)
|
143
157
|
file_contents = []
|
144
|
-
|
145
|
-
File.open(path, "r") do |file|
|
146
|
-
while (line = file.gets) do
|
147
|
-
file_contents << line
|
148
|
-
end
|
149
|
-
end
|
158
|
+
File.open(path).each { |line| file_contents << line }
|
150
159
|
|
151
160
|
file_contents
|
152
161
|
end
|
data/lib/yarn/server.rb
CHANGED
@@ -5,55 +5,64 @@ module Yarn
|
|
5
5
|
|
6
6
|
include Logging
|
7
7
|
|
8
|
-
attr_accessor :host, :port, :socket, :
|
8
|
+
attr_accessor :host, :port, :socket, :workers
|
9
9
|
|
10
|
-
def initialize(
|
10
|
+
def initialize(options={})
|
11
11
|
# merge given options with default values
|
12
|
-
|
12
|
+
opts = {
|
13
13
|
output: $stdout,
|
14
14
|
host: '127.0.0.1',
|
15
|
-
port: 3000
|
16
|
-
|
15
|
+
port: 3000,
|
16
|
+
workers: 4,
|
17
|
+
rack: "off"
|
18
|
+
}.merge(options)
|
17
19
|
|
18
|
-
@app =
|
19
|
-
@
|
20
|
+
@app = nil
|
21
|
+
@app = load_rack_app(opts[:rack]) unless opts[:rack] == "off"
|
20
22
|
|
23
|
+
@host, @port, @num_workers = opts[:host], opts[:port], opts[:workers]
|
24
|
+
@workers = []
|
25
|
+
$output, $debug = opts[:output], opts[:debug]
|
26
|
+
end
|
27
|
+
|
28
|
+
def load_rack_app(app_path)
|
29
|
+
if File.exists?(app_path)
|
30
|
+
config_file = File.read(app_path)
|
31
|
+
rack_application = eval("Rack::Builder.new { #{config_file} }")
|
32
|
+
else
|
33
|
+
log "#{app_path} does not exist. Exiting."
|
34
|
+
Kernel::exit
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
trap("INT") { stop }
|
21
40
|
@socket = TCPServer.new(@host, @port)
|
41
|
+
log "Yarn started #{@num_workers} workers and is listening on #{@host}:#{@port}"
|
22
42
|
|
23
|
-
|
43
|
+
init_workers
|
24
44
|
|
25
|
-
|
45
|
+
# Waits here for all processes to exit
|
46
|
+
Process.waitall
|
26
47
|
end
|
27
48
|
|
28
|
-
def
|
29
|
-
@
|
30
|
-
|
31
|
-
|
49
|
+
def init_workers
|
50
|
+
@num_workers.times do
|
51
|
+
@workers << fork do
|
52
|
+
trap("INT") { exit }
|
53
|
+
loop do
|
54
|
+
handler ||= @app ? RackHandler.new(@app) : RequestHandler.new
|
32
55
|
session = @socket.accept
|
33
|
-
|
34
|
-
rescue Exception => e
|
35
|
-
session.close
|
36
|
-
log e.message
|
37
|
-
log e.backtrace
|
56
|
+
handler.run session
|
38
57
|
end
|
39
58
|
end
|
40
59
|
end
|
41
|
-
|
42
|
-
begin
|
43
|
-
@socket_listener.join
|
44
|
-
rescue Interrupt => e
|
45
|
-
log "Caught interrupt, stopping..."
|
46
|
-
ensure
|
47
|
-
stop
|
48
|
-
end
|
49
60
|
end
|
50
61
|
|
51
62
|
def stop
|
52
|
-
@socket.close if @socket
|
53
|
-
@socket = nil
|
54
|
-
@socket_listener.kill if @socket_listener
|
63
|
+
@socket.close if (@socket && !@socket.closed?)
|
55
64
|
|
56
|
-
log "Server stopped"
|
65
|
+
log "Server stopped. Have a nice day!"
|
57
66
|
end
|
58
67
|
end
|
59
68
|
end
|