puma 2.11.1-java → 2.11.2-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.txt +23 -0
- data/Manifest.txt +1 -0
- data/lib/puma/cli.rb +269 -303
- data/lib/puma/cluster.rb +1 -0
- data/lib/puma/configuration.rb +62 -328
- data/lib/puma/const.rb +1 -1
- data/lib/puma/dsl.rb +280 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/server.rb +24 -7
- data/puma.gemspec +1 -1
- data/test/test_cli.rb +12 -12
- data/test/test_config.rb +26 -0
- data/test/test_persistent.rb +2 -2
- data/test/test_puma_server.rb +113 -1
- data/test/test_unix_socket.rb +10 -10
- metadata +3 -2
data/lib/puma/const.rb
CHANGED
data/lib/puma/dsl.rb
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
module Puma
|
2
|
+
# The methods that are available for use inside the config file.
|
3
|
+
#
|
4
|
+
class DSL
|
5
|
+
include ConfigDefault
|
6
|
+
|
7
|
+
def self.load(options, path)
|
8
|
+
new(options).tap do |obj|
|
9
|
+
obj._load_from(path)
|
10
|
+
end
|
11
|
+
|
12
|
+
options
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def _load_from(path)
|
20
|
+
instance_eval(File.read(path), path, 1) if path
|
21
|
+
end
|
22
|
+
|
23
|
+
# Use +obj+ or +block+ as the Rack app. This allows a config file to
|
24
|
+
# be the app itself.
|
25
|
+
#
|
26
|
+
def app(obj=nil, &block)
|
27
|
+
obj ||= block
|
28
|
+
|
29
|
+
raise "Provide either a #call'able or a block" unless obj
|
30
|
+
|
31
|
+
@options[:app] = obj
|
32
|
+
end
|
33
|
+
|
34
|
+
# Start the Puma control rack app on +url+. This app can be communicated
|
35
|
+
# with to control the main server.
|
36
|
+
#
|
37
|
+
def activate_control_app(url="auto", opts=nil)
|
38
|
+
@options[:control_url] = url
|
39
|
+
|
40
|
+
if opts
|
41
|
+
auth_token = opts[:auth_token]
|
42
|
+
@options[:control_auth_token] = auth_token if auth_token
|
43
|
+
|
44
|
+
@options[:control_auth_token] = :none if opts[:no_token]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Bind the server to +url+. tcp:// and unix:// are the only accepted
|
49
|
+
# protocols.
|
50
|
+
#
|
51
|
+
def bind(url)
|
52
|
+
@options[:binds] << url
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
56
|
+
#
|
57
|
+
def port(port)
|
58
|
+
@options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
|
59
|
+
end
|
60
|
+
|
61
|
+
# Work around leaky apps that leave garbage in Thread locals
|
62
|
+
# across requests
|
63
|
+
#
|
64
|
+
def clean_thread_locals(which=true)
|
65
|
+
@options[:clean_thread_locals] = which
|
66
|
+
end
|
67
|
+
|
68
|
+
# Daemonize the server into the background. Highly suggest that
|
69
|
+
# this be combined with +pidfile+ and +stdout_redirect+.
|
70
|
+
def daemonize(which=true)
|
71
|
+
@options[:daemon] = which
|
72
|
+
end
|
73
|
+
|
74
|
+
# When shutting down, drain the accept socket of pending
|
75
|
+
# connections and proces them. This loops over the accept
|
76
|
+
# socket until there are no more read events and then stops
|
77
|
+
# looking and waits for the requests to finish.
|
78
|
+
def drain_on_shutdown(which=true)
|
79
|
+
@options[:drain_on_shutdown] = which
|
80
|
+
end
|
81
|
+
|
82
|
+
# Set the environment in which the Rack's app will run.
|
83
|
+
def environment(environment)
|
84
|
+
@options[:environment] = environment
|
85
|
+
end
|
86
|
+
|
87
|
+
# Code to run before doing a restart. This code should
|
88
|
+
# close logfiles, database connections, etc.
|
89
|
+
#
|
90
|
+
# This can be called multiple times to add code each time.
|
91
|
+
#
|
92
|
+
def on_restart(&block)
|
93
|
+
@options[:on_restart] << block
|
94
|
+
end
|
95
|
+
|
96
|
+
# Command to use to restart puma. This should be just how to
|
97
|
+
# load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
|
98
|
+
# to puma, as those are the same as the original process.
|
99
|
+
#
|
100
|
+
def restart_command(cmd)
|
101
|
+
@options[:restart_cmd] = cmd
|
102
|
+
end
|
103
|
+
|
104
|
+
# Store the pid of the server in the file at +path+.
|
105
|
+
def pidfile(path)
|
106
|
+
@options[:pidfile] = path
|
107
|
+
end
|
108
|
+
|
109
|
+
# Disable request logging.
|
110
|
+
#
|
111
|
+
def quiet
|
112
|
+
@options[:quiet] = true
|
113
|
+
end
|
114
|
+
|
115
|
+
# Load +path+ as a rackup file.
|
116
|
+
#
|
117
|
+
def rackup(path)
|
118
|
+
@options[:rackup] = path.to_s
|
119
|
+
end
|
120
|
+
|
121
|
+
# Redirect STDOUT and STDERR to files specified.
|
122
|
+
def stdout_redirect(stdout=nil, stderr=nil, append=false)
|
123
|
+
@options[:redirect_stdout] = stdout
|
124
|
+
@options[:redirect_stderr] = stderr
|
125
|
+
@options[:redirect_append] = append
|
126
|
+
end
|
127
|
+
|
128
|
+
# Configure +min+ to be the minimum number of threads to use to answer
|
129
|
+
# requests and +max+ the maximum.
|
130
|
+
#
|
131
|
+
def threads(min, max)
|
132
|
+
min = Integer(min)
|
133
|
+
max = Integer(max)
|
134
|
+
if min > max
|
135
|
+
raise "The minimum (#{min}) number of threads must be less than the max (#{max})"
|
136
|
+
end
|
137
|
+
|
138
|
+
@options[:min_threads] = min
|
139
|
+
@options[:max_threads] = max
|
140
|
+
end
|
141
|
+
|
142
|
+
def ssl_bind(host, port, opts)
|
143
|
+
@options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
|
144
|
+
end
|
145
|
+
|
146
|
+
# Use +path+ as the file to store the server info state. This is
|
147
|
+
# used by pumactl to query and control the server.
|
148
|
+
#
|
149
|
+
def state_path(path)
|
150
|
+
@options[:state] = path.to_s
|
151
|
+
end
|
152
|
+
|
153
|
+
# *Cluster mode only* How many worker processes to run.
|
154
|
+
#
|
155
|
+
def workers(count)
|
156
|
+
@options[:workers] = count.to_i
|
157
|
+
end
|
158
|
+
|
159
|
+
# *Cluster mode only* Code to run immediately before a worker shuts
|
160
|
+
# down (after it has finished processing HTTP requests). These hooks
|
161
|
+
# can block if necessary to wait for background operations unknown
|
162
|
+
# to puma to finish before the process terminates.
|
163
|
+
#
|
164
|
+
# This can be called multiple times to add hooks.
|
165
|
+
#
|
166
|
+
def on_worker_shutdown(&block)
|
167
|
+
@options[:before_worker_shutdown] << block
|
168
|
+
end
|
169
|
+
|
170
|
+
# *Cluster mode only* Code to run when a worker boots to setup
|
171
|
+
# the process before booting the app.
|
172
|
+
#
|
173
|
+
# This can be called multiple times to add hooks.
|
174
|
+
#
|
175
|
+
def on_worker_boot(&block)
|
176
|
+
@options[:before_worker_boot] << block
|
177
|
+
end
|
178
|
+
|
179
|
+
# *Cluster mode only* Code to run when a master process is
|
180
|
+
# about to create the worker by forking itself.
|
181
|
+
#
|
182
|
+
# This can be called multiple times to add hooks.
|
183
|
+
#
|
184
|
+
def on_worker_fork(&block)
|
185
|
+
@options[:before_worker_fork] << block
|
186
|
+
end
|
187
|
+
|
188
|
+
# *Cluster mode only* Code to run when a worker boots to setup
|
189
|
+
# the process after booting the app.
|
190
|
+
#
|
191
|
+
# This can be called multiple times to add hooks.
|
192
|
+
#
|
193
|
+
def after_worker_boot(&block)
|
194
|
+
@options[:after_worker_boot] << block
|
195
|
+
end
|
196
|
+
|
197
|
+
# The directory to operate out of.
|
198
|
+
def directory(dir)
|
199
|
+
@options[:directory] = dir.to_s
|
200
|
+
@options[:worker_directory] = dir.to_s
|
201
|
+
end
|
202
|
+
|
203
|
+
# Run the app as a raw TCP app instead of an HTTP rack app
|
204
|
+
def tcp_mode
|
205
|
+
@options[:mode] = :tcp
|
206
|
+
end
|
207
|
+
|
208
|
+
# *Cluster mode only* Preload the application before starting
|
209
|
+
# the workers and setting up the listen ports. This conflicts
|
210
|
+
# with using the phased restart feature, you can't use both.
|
211
|
+
#
|
212
|
+
def preload_app!(answer=true)
|
213
|
+
@options[:preload_app] = answer
|
214
|
+
end
|
215
|
+
|
216
|
+
# Use +obj+ or +block+ as the low level error handler. This allows a config file to
|
217
|
+
# change the default error on the server.
|
218
|
+
#
|
219
|
+
def lowlevel_error_handler(obj=nil, &block)
|
220
|
+
obj ||= block
|
221
|
+
raise "Provide either a #call'able or a block" unless obj
|
222
|
+
@options[:lowlevel_error_handler] = obj
|
223
|
+
end
|
224
|
+
|
225
|
+
# This option is used to allow your app and its gems to be
|
226
|
+
# properly reloaded when not using preload.
|
227
|
+
#
|
228
|
+
# When set, if puma detects that it's been invoked in the
|
229
|
+
# context of Bundler, it will cleanup the environment and
|
230
|
+
# re-run itself outside the Bundler environment, but directly
|
231
|
+
# using the files that Bundler has setup.
|
232
|
+
#
|
233
|
+
# This means that puma is now decoupled from your Bundler
|
234
|
+
# context and when each worker loads, it will be loading a
|
235
|
+
# new Bundler context and thus can float around as the release
|
236
|
+
# dictates.
|
237
|
+
def prune_bundler(answer=true)
|
238
|
+
@options[:prune_bundler] = answer
|
239
|
+
end
|
240
|
+
|
241
|
+
# Additional text to display in process listing
|
242
|
+
def tag(string)
|
243
|
+
@options[:tag] = string
|
244
|
+
end
|
245
|
+
|
246
|
+
# *Cluster mode only* Set the timeout for workers
|
247
|
+
def worker_timeout(timeout)
|
248
|
+
@options[:worker_timeout] = timeout
|
249
|
+
end
|
250
|
+
|
251
|
+
# *Cluster mode only* Set the timeout for worker shutdown
|
252
|
+
def worker_shutdown_timeout(timeout)
|
253
|
+
@options[:worker_shutdown_timeout] = timeout
|
254
|
+
end
|
255
|
+
|
256
|
+
# When set to true (the default), workers accept all requests
|
257
|
+
# and queue them before passing them to the handlers.
|
258
|
+
# When set to false, each worker process accepts exactly as
|
259
|
+
# many requests as it is configured to simultaneously handle.
|
260
|
+
#
|
261
|
+
# Queueing requests generally improves performance. In some
|
262
|
+
# cases, such as a single threaded application, it may be
|
263
|
+
# better to ensure requests get balanced across workers.
|
264
|
+
#
|
265
|
+
# Note that setting this to false disables HTTP keepalive and
|
266
|
+
# slow clients will occupy a handler thread while the request
|
267
|
+
# is being sent. A reverse proxy, such as nginx, can handle
|
268
|
+
# slow clients and queue requests before they reach puma.
|
269
|
+
def queue_requests(answer=true)
|
270
|
+
@options[:queue_requests] = answer
|
271
|
+
end
|
272
|
+
|
273
|
+
# When a shutdown is requested, the backtraces of all the
|
274
|
+
# threads will be written to $stdout. This can help figure
|
275
|
+
# out why shutdown is hanging.
|
276
|
+
def shutdown_debug(val=true)
|
277
|
+
@options[:shutdown_debug] = val
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
data/lib/puma/puma_http11.jar
CHANGED
Binary file
|
data/lib/puma/server.rb
CHANGED
@@ -535,7 +535,7 @@ module Puma
|
|
535
535
|
line_ending = LINE_END
|
536
536
|
colon = COLON
|
537
537
|
|
538
|
-
if env[HTTP_VERSION] == HTTP_11
|
538
|
+
http_11 = if env[HTTP_VERSION] == HTTP_11
|
539
539
|
allow_chunked = true
|
540
540
|
keep_alive = env[HTTP_CONNECTION] != CLOSE
|
541
541
|
include_keepalive_header = false
|
@@ -552,6 +552,7 @@ module Puma
|
|
552
552
|
|
553
553
|
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
|
554
554
|
end
|
555
|
+
true
|
555
556
|
else
|
556
557
|
allow_chunked = false
|
557
558
|
keep_alive = env[HTTP_CONNECTION] == KEEP_ALIVE
|
@@ -567,6 +568,7 @@ module Puma
|
|
567
568
|
|
568
569
|
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
|
569
570
|
end
|
571
|
+
false
|
570
572
|
end
|
571
573
|
|
572
574
|
response_hijack = nil
|
@@ -593,6 +595,12 @@ module Puma
|
|
593
595
|
end
|
594
596
|
end
|
595
597
|
|
598
|
+
if include_keepalive_header
|
599
|
+
lines << CONNECTION_KEEP_ALIVE
|
600
|
+
elsif http_11 && !keep_alive
|
601
|
+
lines << CONNECTION_CLOSE
|
602
|
+
end
|
603
|
+
|
596
604
|
if no_body
|
597
605
|
if content_length and status != 204
|
598
606
|
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
|
@@ -603,12 +611,6 @@ module Puma
|
|
603
611
|
return keep_alive
|
604
612
|
end
|
605
613
|
|
606
|
-
if include_keepalive_header
|
607
|
-
lines << CONNECTION_KEEP_ALIVE
|
608
|
-
elsif !keep_alive
|
609
|
-
lines << CONNECTION_CLOSE
|
610
|
-
end
|
611
|
-
|
612
614
|
unless response_hijack
|
613
615
|
if content_length
|
614
616
|
lines.append CONTENT_LENGTH_S, content_length.to_s, line_ending
|
@@ -738,6 +740,21 @@ module Puma
|
|
738
740
|
# Wait for all outstanding requests to finish.
|
739
741
|
#
|
740
742
|
def graceful_shutdown
|
743
|
+
if @options[:shutdown_debug]
|
744
|
+
threads = Thread.list
|
745
|
+
total = threads.size
|
746
|
+
|
747
|
+
pid = Process.pid
|
748
|
+
|
749
|
+
$stdout.syswrite "#{pid}: === Begin thread backtrace dump ===\n"
|
750
|
+
|
751
|
+
threads.each_with_index do |t,i|
|
752
|
+
$stdout.syswrite "#{pid}: Thread #{i+1}/#{total}: #{t.inspect}\n"
|
753
|
+
$stdout.syswrite "#{pid}: #{t.backtrace.join("\n#{pid}: ")}\n\n"
|
754
|
+
end
|
755
|
+
$stdout.syswrite "#{pid}: === End thread backtrace dump ===\n"
|
756
|
+
end
|
757
|
+
|
741
758
|
if @options[:drain_on_shutdown]
|
742
759
|
count = 0
|
743
760
|
|
data/puma.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
18
18
|
s.authors = ["Evan Phoenix"]
|
19
19
|
s.date = `git log --pretty="%ai" -n 1`.split(" ").first
|
20
|
-
s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a
|
20
|
+
s.description = "Puma is a simple, fast, threaded, and highly concurrent HTTP 1.1 server for Ruby/Rack applications. Puma is intended for use in both development and production environments. In order to get the best throughput, it is highly recommended that you use a Ruby implementation with real threads like Rubinius or JRuby."
|
21
21
|
s.email = ["evan@phx.io"]
|
22
22
|
s.executables = ["puma", "pumactl"]
|
23
23
|
s.extensions = ["ext/puma_http11/extconf.rb"]
|
data/test/test_cli.rb
CHANGED
@@ -35,7 +35,7 @@ class TestCLI < Test::Unit::TestCase
|
|
35
35
|
|
36
36
|
def test_pid_file
|
37
37
|
cli = Puma::CLI.new ["--pidfile", @tmp_path]
|
38
|
-
cli.parse_options
|
38
|
+
cli.send(:parse_options)
|
39
39
|
cli.write_pid
|
40
40
|
|
41
41
|
assert_equal File.read(@tmp_path).strip.to_i, Process.pid
|
@@ -48,7 +48,7 @@ class TestCLI < Test::Unit::TestCase
|
|
48
48
|
"--control-token", "",
|
49
49
|
"test/lobster.ru"], @events
|
50
50
|
|
51
|
-
cli.parse_options
|
51
|
+
cli.send(:parse_options)
|
52
52
|
|
53
53
|
thread_exception = nil
|
54
54
|
t = Thread.new do
|
@@ -57,7 +57,7 @@ class TestCLI < Test::Unit::TestCase
|
|
57
57
|
rescue Exception => e
|
58
58
|
thread_exception = e
|
59
59
|
end
|
60
|
-
end
|
60
|
+
end
|
61
61
|
|
62
62
|
wait_booted
|
63
63
|
|
@@ -79,7 +79,7 @@ class TestCLI < Test::Unit::TestCase
|
|
79
79
|
"--control", url,
|
80
80
|
"--control-token", "",
|
81
81
|
"test/lobster.ru"], @events
|
82
|
-
cli.parse_options
|
82
|
+
cli.send(:parse_options)
|
83
83
|
|
84
84
|
t = Thread.new { cli.run }
|
85
85
|
|
@@ -102,7 +102,7 @@ class TestCLI < Test::Unit::TestCase
|
|
102
102
|
"--control", url,
|
103
103
|
"--control-token", "",
|
104
104
|
"test/lobster.ru"], @events
|
105
|
-
cli.parse_options
|
105
|
+
cli.send(:parse_options)
|
106
106
|
|
107
107
|
t = Thread.new { cli.run }
|
108
108
|
|
@@ -120,7 +120,7 @@ class TestCLI < Test::Unit::TestCase
|
|
120
120
|
def test_tmp_control
|
121
121
|
url = "tcp://127.0.0.1:8232"
|
122
122
|
cli = Puma::CLI.new ["--state", @tmp_path, "--control", "auto"]
|
123
|
-
cli.parse_options
|
123
|
+
cli.send(:parse_options)
|
124
124
|
cli.write_state
|
125
125
|
|
126
126
|
data = YAML.load File.read(@tmp_path)
|
@@ -138,7 +138,7 @@ class TestCLI < Test::Unit::TestCase
|
|
138
138
|
def test_state
|
139
139
|
url = "tcp://127.0.0.1:8232"
|
140
140
|
cli = Puma::CLI.new ["--state", @tmp_path, "--control", url]
|
141
|
-
cli.parse_options
|
141
|
+
cli.send(:parse_options)
|
142
142
|
cli.write_state
|
143
143
|
|
144
144
|
data = YAML.load File.read(@tmp_path)
|
@@ -149,13 +149,13 @@ class TestCLI < Test::Unit::TestCase
|
|
149
149
|
|
150
150
|
def test_load_path
|
151
151
|
cli = Puma::CLI.new ["--include", 'foo/bar']
|
152
|
-
cli.parse_options
|
152
|
+
cli.send(:parse_options)
|
153
153
|
|
154
154
|
assert_equal 'foo/bar', $LOAD_PATH[0]
|
155
155
|
$LOAD_PATH.shift
|
156
156
|
|
157
157
|
cli = Puma::CLI.new ["--include", 'foo/bar:baz/qux']
|
158
|
-
cli.parse_options
|
158
|
+
cli.send(:parse_options)
|
159
159
|
|
160
160
|
assert_equal 'foo/bar', $LOAD_PATH[0]
|
161
161
|
$LOAD_PATH.shift
|
@@ -165,9 +165,9 @@ class TestCLI < Test::Unit::TestCase
|
|
165
165
|
|
166
166
|
def test_environment
|
167
167
|
cli = Puma::CLI.new ["--environment", @environment]
|
168
|
-
cli.parse_options
|
169
|
-
cli.set_rack_environment
|
168
|
+
cli.send(:parse_options)
|
169
|
+
cli.send(:set_rack_environment)
|
170
170
|
|
171
|
-
assert_equal ENV['RACK_ENV'], @environment
|
171
|
+
assert_equal ENV['RACK_ENV'], @environment
|
172
172
|
end
|
173
173
|
end
|