puma 2.1.1 → 7.2.1
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.
- checksums.yaml +7 -0
- data/History.md +3273 -0
- data/LICENSE +23 -20
- data/README.md +388 -100
- data/bin/puma-wild +25 -0
- data/bin/pumactl +1 -1
- data/docs/architecture.md +74 -0
- data/docs/compile_options.md +55 -0
- data/docs/deployment.md +137 -0
- data/docs/fork_worker.md +41 -0
- data/docs/images/puma-connection-flow-no-reactor.png +0 -0
- data/docs/images/puma-connection-flow.png +0 -0
- data/docs/images/puma-general-arch.png +0 -0
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +9 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -0
- data/docs/kubernetes.md +73 -0
- data/docs/nginx.md +5 -5
- data/docs/plugins.md +42 -0
- data/docs/rails_dev_mode.md +28 -0
- data/docs/restart.md +65 -0
- data/docs/signals.md +98 -0
- data/docs/stats.md +148 -0
- data/docs/systemd.md +253 -0
- data/docs/testing_benchmarks_local_files.md +150 -0
- data/docs/testing_test_rackup_ci_files.md +36 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +59 -2
- data/ext/puma_http11/http11_parser.c +319 -487
- data/ext/puma_http11/http11_parser.h +15 -13
- data/ext/puma_http11/http11_parser.java.rl +27 -43
- data/ext/puma_http11/http11_parser.rl +27 -24
- data/ext/puma_http11/http11_parser_common.rl +8 -8
- data/ext/puma_http11/mini_ssl.c +696 -38
- data/ext/puma_http11/no_ssl/PumaHttp11Service.java +15 -0
- data/ext/puma_http11/org/jruby/puma/Http11.java +145 -113
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +139 -172
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +413 -193
- data/ext/puma_http11/puma_http11.c +183 -175
- data/lib/puma/app/status.rb +77 -29
- data/lib/puma/binder.rb +349 -119
- data/lib/puma/cli.rb +164 -769
- data/lib/puma/client.rb +591 -132
- data/lib/puma/cluster/worker.rb +183 -0
- data/lib/puma/cluster/worker_handle.rb +127 -0
- data/lib/puma/cluster.rb +634 -0
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +115 -0
- data/lib/puma/configuration.rb +370 -202
- data/lib/puma/const.rb +266 -115
- data/lib/puma/control_cli.rb +219 -120
- data/lib/puma/detect.rb +45 -2
- data/lib/puma/dsl.rb +1496 -0
- data/lib/puma/error_logger.rb +115 -0
- data/lib/puma/events.rb +44 -60
- data/lib/puma/io_buffer.rb +48 -5
- data/lib/puma/jruby_restart.rb +2 -51
- data/lib/puma/json_serialization.rb +96 -0
- data/lib/puma/launcher/bundle_pruner.rb +104 -0
- data/lib/puma/launcher.rb +502 -0
- data/lib/puma/log_writer.rb +147 -0
- data/lib/puma/minissl/context_builder.rb +96 -0
- data/lib/puma/minissl.rb +355 -37
- data/lib/puma/null_io.rb +79 -12
- data/lib/puma/plugin/systemd.rb +90 -0
- data/lib/puma/plugin/tmp_restart.rb +36 -0
- data/lib/puma/plugin.rb +111 -0
- data/lib/puma/rack/builder.rb +297 -0
- data/lib/puma/rack/urlmap.rb +93 -0
- data/lib/puma/rack_default.rb +21 -4
- data/lib/puma/reactor.rb +102 -133
- data/lib/puma/request.rb +703 -0
- data/lib/puma/runner.rb +211 -0
- data/lib/puma/sd_notify.rb +146 -0
- data/lib/puma/server.rb +544 -436
- data/lib/puma/single.rb +72 -0
- data/lib/puma/state_file.rb +69 -0
- data/lib/puma/thread_pool.rb +282 -56
- data/lib/puma/util.rb +125 -0
- data/lib/puma.rb +80 -6
- data/lib/rack/handler/puma.rb +125 -47
- data/tools/Dockerfile +26 -0
- data/tools/trickletest.rb +44 -0
- metadata +77 -148
- data/COPYING +0 -55
- data/Gemfile +0 -10
- data/History.txt +0 -291
- data/Manifest.txt +0 -60
- data/Rakefile +0 -121
- data/TODO +0 -5
- data/docs/config.md +0 -0
- data/ext/puma_http11/ext_help.h +0 -15
- data/ext/puma_http11/io_buffer.c +0 -154
- data/lib/puma/accept_nonblock.rb +0 -23
- data/lib/puma/capistrano.rb +0 -34
- data/lib/puma/compat.rb +0 -11
- data/lib/puma/daemon_ext.rb +0 -20
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack_patch.rb +0 -25
- data/puma.gemspec +0 -45
- data/test/test_app_status.rb +0 -88
- data/test/test_cli.rb +0 -171
- data/test/test_config.rb +0 -16
- data/test/test_http10.rb +0 -27
- data/test/test_http11.rb +0 -126
- data/test/test_integration.rb +0 -154
- data/test/test_iobuffer.rb +0 -38
- data/test/test_minissl.rb +0 -25
- data/test/test_null_io.rb +0 -31
- data/test/test_persistent.rb +0 -238
- data/test/test_puma_server.rb +0 -207
- data/test/test_rack_handler.rb +0 -10
- data/test/test_rack_server.rb +0 -141
- data/test/test_thread_pool.rb +0 -146
- data/test/test_unix_socket.rb +0 -39
- data/test/test_ws.rb +0 -89
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -332
- data/tools/jungle/init.d/run-puma +0 -3
- data/tools/jungle/upstart/README.md +0 -61
- data/tools/jungle/upstart/puma-manager.conf +0 -31
- data/tools/jungle/upstart/puma.conf +0 -52
data/lib/puma/cli.rb
CHANGED
|
@@ -1,850 +1,245 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'optparse'
|
|
2
4
|
require 'uri'
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
require 'puma/daemon_ext'
|
|
10
|
-
require 'puma/util'
|
|
11
|
-
|
|
12
|
-
require 'rack/commonlogger'
|
|
13
|
-
require 'rack/utils'
|
|
6
|
+
require_relative '../puma'
|
|
7
|
+
require_relative 'configuration'
|
|
8
|
+
require_relative 'launcher'
|
|
9
|
+
require_relative 'const'
|
|
10
|
+
require_relative 'log_writer'
|
|
14
11
|
|
|
15
12
|
module Puma
|
|
13
|
+
class << self
|
|
14
|
+
# The CLI exports a Puma::Configuration instance here to allow
|
|
15
|
+
# apps to pick it up. An app must load this object conditionally
|
|
16
|
+
# because it is not set if the app is launched via any mechanism
|
|
17
|
+
# other than the CLI class.
|
|
18
|
+
attr_accessor :cli_config
|
|
19
|
+
end
|
|
20
|
+
|
|
16
21
|
# Handles invoke a Puma::Server in a command line style.
|
|
17
22
|
#
|
|
18
23
|
class CLI
|
|
19
24
|
# Create a new CLI object using +argv+ as the command line
|
|
20
25
|
# arguments.
|
|
21
26
|
#
|
|
22
|
-
|
|
23
|
-
# this object will report status on.
|
|
24
|
-
#
|
|
25
|
-
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
|
27
|
+
def initialize(argv, log_writer = LogWriter.stdio, events = Events.new, env: ENV)
|
|
26
28
|
@debug = false
|
|
27
|
-
@argv = argv
|
|
28
|
-
@
|
|
29
|
-
@
|
|
30
|
-
|
|
31
|
-
@phase = 0
|
|
32
|
-
@workers = []
|
|
33
|
-
|
|
34
|
-
@events = Events.new @stdout, @stderr
|
|
35
|
-
|
|
36
|
-
@server = nil
|
|
37
|
-
@status = nil
|
|
38
|
-
|
|
39
|
-
@restart = false
|
|
40
|
-
@phased_state = :idle
|
|
41
|
-
|
|
42
|
-
ENV['NEWRELIC_DISPATCHER'] ||= "puma"
|
|
43
|
-
|
|
44
|
-
setup_options
|
|
45
|
-
|
|
46
|
-
generate_restart_data
|
|
47
|
-
|
|
48
|
-
@binder = Binder.new(@events)
|
|
49
|
-
@binder.import_from_env
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def restart_on_stop!
|
|
53
|
-
@restart = true
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def generate_restart_data
|
|
57
|
-
# Use the same trick as unicorn, namely favor PWD because
|
|
58
|
-
# it will contain an unresolved symlink, useful for when
|
|
59
|
-
# the pwd is /data/releases/current.
|
|
60
|
-
if dir = ENV['PWD']
|
|
61
|
-
s_env = File.stat(dir)
|
|
62
|
-
s_pwd = File.stat(Dir.pwd)
|
|
63
|
-
|
|
64
|
-
if s_env.ino == s_pwd.ino and s_env.dev == s_pwd.dev
|
|
65
|
-
@restart_dir = dir
|
|
66
|
-
@options[:worker_directory] = dir
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
@restart_dir ||= Dir.pwd
|
|
71
|
-
|
|
72
|
-
@original_argv = ARGV.dup
|
|
73
|
-
|
|
74
|
-
if defined? Rubinius::OS_ARGV
|
|
75
|
-
@restart_argv = Rubinius::OS_ARGV
|
|
76
|
-
else
|
|
77
|
-
require 'rubygems'
|
|
78
|
-
|
|
79
|
-
# if $0 is a file in the current directory, then restart
|
|
80
|
-
# it the same, otherwise add -S on there because it was
|
|
81
|
-
# picked up in PATH.
|
|
82
|
-
#
|
|
83
|
-
if File.exists?($0)
|
|
84
|
-
arg0 = [Gem.ruby, $0]
|
|
85
|
-
else
|
|
86
|
-
arg0 = [Gem.ruby, "-S", $0]
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Detect and reinject -Ilib from the command line
|
|
90
|
-
lib = File.expand_path "lib"
|
|
91
|
-
arg0[1,0] = ["-I", lib] if $:[0] == lib
|
|
92
|
-
|
|
93
|
-
@restart_argv = arg0 + ARGV
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def restart!
|
|
98
|
-
@options[:on_restart].each do |blk|
|
|
99
|
-
blk.call self
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
if jruby?
|
|
103
|
-
@binder.listeners.each_with_index do |(str,io),i|
|
|
104
|
-
io.close
|
|
105
|
-
|
|
106
|
-
# We have to unlink a unix socket path that's not being used
|
|
107
|
-
uri = URI.parse str
|
|
108
|
-
if uri.scheme == "unix"
|
|
109
|
-
path = "#{uri.host}#{uri.path}"
|
|
110
|
-
File.unlink path
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
require 'puma/jruby_restart'
|
|
115
|
-
JRubyRestart.chdir_exec(@restart_dir, @restart_argv)
|
|
116
|
-
else
|
|
117
|
-
redirects = {:close_others => true}
|
|
118
|
-
@binder.listeners.each_with_index do |(l,io),i|
|
|
119
|
-
ENV["PUMA_INHERIT_#{i}"] = "#{io.to_i}:#{l}"
|
|
120
|
-
redirects[io.to_i] = io.to_i
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
if cmd = @options[:restart_cmd]
|
|
124
|
-
argv = cmd.split(' ') + @original_argv
|
|
125
|
-
else
|
|
126
|
-
argv = @restart_argv
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
Dir.chdir @restart_dir
|
|
130
|
-
|
|
131
|
-
argv += [redirects] unless RUBY_VERSION < '1.9'
|
|
132
|
-
Kernel.exec(*argv)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# Delegate +log+ to +@events+
|
|
137
|
-
#
|
|
138
|
-
def log(str)
|
|
139
|
-
@events.log str
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
# Delegate +error+ to +@events+
|
|
143
|
-
#
|
|
144
|
-
def error(str)
|
|
145
|
-
@events.error str
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def debug(str)
|
|
149
|
-
if @options[:debug]
|
|
150
|
-
@events.log "- #{str}"
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def jruby?
|
|
155
|
-
IS_JRUBY
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def windows?
|
|
159
|
-
RUBY_PLATFORM =~ /mswin32|ming32/
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
def unsupported(str, cond=true)
|
|
163
|
-
return unless cond
|
|
164
|
-
@events.error str
|
|
165
|
-
raise UnsupportedOption
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Build the OptionParser object to handle the available options.
|
|
169
|
-
#
|
|
170
|
-
def setup_options
|
|
171
|
-
@options = {
|
|
172
|
-
:min_threads => 0,
|
|
173
|
-
:max_threads => 16,
|
|
174
|
-
:quiet => false,
|
|
175
|
-
:debug => false,
|
|
176
|
-
:binds => [],
|
|
177
|
-
:workers => 0,
|
|
178
|
-
:daemon => false,
|
|
179
|
-
:worker_boot => []
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
@parser = OptionParser.new do |o|
|
|
183
|
-
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
|
184
|
-
@options[:binds] << arg
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
|
|
188
|
-
@options[:config_file] = arg
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
o.on "--control URL", "The bind url to use for the control server",
|
|
192
|
-
"Use 'auto' to use temp unix server" do |arg|
|
|
193
|
-
if arg
|
|
194
|
-
@options[:control_url] = arg
|
|
195
|
-
elsif jruby?
|
|
196
|
-
unsupported "No default url available on JRuby"
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
o.on "--control-token TOKEN",
|
|
201
|
-
"The token to use as authentication for the control server" do |arg|
|
|
202
|
-
@options[:control_auth_token] = arg
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
o.on "-d", "--daemon", "Daemonize the server into the background" do
|
|
206
|
-
@options[:daemon] = true
|
|
207
|
-
@options[:quiet] = true
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
o.on "--debug", "Log lowlevel debugging information" do
|
|
211
|
-
@options[:debug] = true
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
o.on "--dir DIR", "Change to DIR before starting" do |d|
|
|
215
|
-
@options[:directory] = d.to_s
|
|
216
|
-
@options[:worker_directory] = d.to_s
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
o.on "-e", "--environment ENVIRONMENT",
|
|
220
|
-
"The environment to run the Rack app on (default development)" do |arg|
|
|
221
|
-
@options[:environment] = arg
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
o.on "-I", "--include PATH", "Specify $LOAD_PATH directories" do |arg|
|
|
225
|
-
$LOAD_PATH.unshift(*arg.split(':'))
|
|
226
|
-
end
|
|
29
|
+
@argv = argv.dup
|
|
30
|
+
@log_writer = log_writer
|
|
31
|
+
@events = events
|
|
227
32
|
|
|
228
|
-
|
|
229
|
-
"Use -b for more advanced options" do |arg|
|
|
230
|
-
@options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{arg}"
|
|
231
|
-
end
|
|
33
|
+
@conf = nil
|
|
232
34
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
35
|
+
@stdout = nil
|
|
36
|
+
@stderr = nil
|
|
37
|
+
@append = false
|
|
236
38
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
o.on "-R", "--restart-cmd CMD",
|
|
242
|
-
"The puma command to run during a hot restart",
|
|
243
|
-
"Default: inferred" do |cmd|
|
|
244
|
-
@options[:restart_cmd] = cmd
|
|
245
|
-
end
|
|
39
|
+
@control_url = nil
|
|
40
|
+
@control_options = {}
|
|
246
41
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
end
|
|
42
|
+
begin
|
|
43
|
+
setup_options env
|
|
250
44
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
@options[:min_threads] = min.to_i
|
|
255
|
-
@options[:max_threads] = max.to_i
|
|
256
|
-
else
|
|
257
|
-
@options[:min_threads] = 0
|
|
258
|
-
@options[:max_threads] = arg.to_i
|
|
45
|
+
if file = @argv.shift
|
|
46
|
+
@conf.configure do |user_config, file_config|
|
|
47
|
+
file_config.rackup file
|
|
259
48
|
end
|
|
260
49
|
end
|
|
261
|
-
|
|
262
|
-
o.on "-V", "--version", "Print the version information" do
|
|
263
|
-
puts "puma version #{Puma::Const::VERSION}"
|
|
264
|
-
exit 1
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
o.on "-w", "--workers COUNT",
|
|
268
|
-
"Activate cluster mode: How many worker processes to create" do |arg|
|
|
269
|
-
@options[:workers] = arg.to_i
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
@parser.banner = "puma <options> <rackup file>"
|
|
275
|
-
|
|
276
|
-
@parser.on_tail "-h", "--help", "Show help" do
|
|
277
|
-
log @parser
|
|
50
|
+
rescue UnsupportedOption
|
|
278
51
|
exit 1
|
|
279
52
|
end
|
|
280
|
-
end
|
|
281
53
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def write_pid
|
|
286
|
-
if path = @options[:pidfile]
|
|
287
|
-
File.open(path, "w") do |f|
|
|
288
|
-
f.puts Process.pid
|
|
54
|
+
@conf.configure do |user_config, file_config|
|
|
55
|
+
if @stdout || @stderr
|
|
56
|
+
user_config.stdout_redirect @stdout, @stderr, @append
|
|
289
57
|
end
|
|
290
|
-
end
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
def set_rack_environment
|
|
294
|
-
# Try the user option first, then the environment variable,
|
|
295
|
-
# finally default to development
|
|
296
|
-
|
|
297
|
-
env = @options[:environment] ||
|
|
298
|
-
ENV['RACK_ENV'] ||
|
|
299
|
-
'development'
|
|
300
|
-
|
|
301
|
-
@options[:environment] = env
|
|
302
|
-
ENV['RACK_ENV'] = env
|
|
303
|
-
end
|
|
304
|
-
|
|
305
|
-
def delete_pidfile
|
|
306
|
-
if path = @options[:pidfile]
|
|
307
|
-
File.unlink path
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
def write_state
|
|
312
|
-
write_pid
|
|
313
|
-
|
|
314
|
-
require 'yaml'
|
|
315
|
-
|
|
316
|
-
if path = @options[:state]
|
|
317
|
-
state = { "pid" => Process.pid }
|
|
318
|
-
|
|
319
|
-
cfg = @config.dup
|
|
320
|
-
|
|
321
|
-
[ :logger, :worker_boot, :on_restart ].each { |o| cfg.options.delete o }
|
|
322
|
-
|
|
323
|
-
state["config"] = cfg
|
|
324
58
|
|
|
325
|
-
|
|
326
|
-
|
|
59
|
+
if @control_url
|
|
60
|
+
user_config.activate_control_app @control_url, @control_options
|
|
327
61
|
end
|
|
328
62
|
end
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
# :nodoc:
|
|
332
|
-
def parse_options
|
|
333
|
-
@parser.parse! @argv
|
|
334
|
-
|
|
335
|
-
if @argv.last
|
|
336
|
-
@options[:rackup] = @argv.shift
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
@config = Puma::Configuration.new @options
|
|
340
|
-
|
|
341
|
-
# Advertise the Configuration
|
|
342
|
-
Puma.cli_config = @config
|
|
343
|
-
|
|
344
|
-
@config.load
|
|
345
|
-
|
|
346
|
-
if @options[:workers] > 0
|
|
347
|
-
unsupported "worker mode not supported on JRuby and Windows",
|
|
348
|
-
jruby? || windows?
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
63
|
|
|
352
|
-
|
|
353
|
-
log " - Gracefully stopping, waiting for requests to finish"
|
|
354
|
-
@status.stop(true) if @status
|
|
355
|
-
server.stop(true)
|
|
356
|
-
delete_pidfile
|
|
357
|
-
log " - Goodbye!"
|
|
64
|
+
@launcher = Puma::Launcher.new(@conf, env: ENV, log_writer: @log_writer, events: @events, argv: argv)
|
|
358
65
|
end
|
|
359
66
|
|
|
360
|
-
|
|
361
|
-
stdout = @options[:redirect_stdout]
|
|
362
|
-
stderr = @options[:redirect_stderr]
|
|
363
|
-
append = @options[:redirect_append]
|
|
364
|
-
|
|
365
|
-
if stdout
|
|
366
|
-
STDOUT.reopen stdout, (append ? "a" : "w")
|
|
367
|
-
STDOUT.sync = true
|
|
368
|
-
STDOUT.puts "=== puma startup: #{Time.now} ==="
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
if stderr
|
|
372
|
-
STDERR.reopen stderr, (append ? "a" : "w")
|
|
373
|
-
STDERR.sync = true
|
|
374
|
-
STDERR.puts "=== puma startup: #{Time.now} ==="
|
|
375
|
-
end
|
|
376
|
-
end
|
|
67
|
+
attr_reader :launcher
|
|
377
68
|
|
|
378
69
|
# Parse the options, load the rackup, start the server and wait
|
|
379
70
|
# for it to finish.
|
|
380
71
|
#
|
|
381
72
|
def run
|
|
382
|
-
|
|
383
|
-
parse_options
|
|
384
|
-
rescue UnsupportedOption
|
|
385
|
-
exit 1
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
if dir = @options[:directory]
|
|
389
|
-
Dir.chdir dir
|
|
390
|
-
end
|
|
391
|
-
|
|
392
|
-
clustered = @options[:workers] > 0
|
|
393
|
-
|
|
394
|
-
if clustered
|
|
395
|
-
@events = PidEvents.new STDOUT, STDERR
|
|
396
|
-
@options[:logger] = @events
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
set_rack_environment
|
|
400
|
-
|
|
401
|
-
if clustered
|
|
402
|
-
run_cluster
|
|
403
|
-
else
|
|
404
|
-
run_single
|
|
405
|
-
end
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
def daemon?
|
|
409
|
-
@options[:daemon]
|
|
410
|
-
end
|
|
411
|
-
|
|
412
|
-
def jruby_daemon?
|
|
413
|
-
daemon? and jruby?
|
|
73
|
+
@launcher.run
|
|
414
74
|
end
|
|
415
75
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
log "Puma #{Puma::Const::PUMA_VERSION} starting..."
|
|
421
|
-
log "* Min threads: #{min_t}, max threads: #{max_t}"
|
|
422
|
-
log "* Environment: #{ENV['RACK_ENV']}"
|
|
76
|
+
private
|
|
77
|
+
def unsupported(str)
|
|
78
|
+
@log_writer.error(str)
|
|
79
|
+
raise UnsupportedOption
|
|
423
80
|
end
|
|
424
81
|
|
|
425
|
-
def
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
app = Puma::App::Status.new server, self
|
|
431
|
-
|
|
432
|
-
if token = @options[:control_auth_token]
|
|
433
|
-
app.auth_token = token unless token.empty? or token == :none
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
status = Puma::Server.new app, @events
|
|
437
|
-
status.min_threads = 0
|
|
438
|
-
status.max_threads = 1
|
|
439
|
-
|
|
440
|
-
case uri.scheme
|
|
441
|
-
when "tcp"
|
|
442
|
-
log "* Starting status server on #{str}"
|
|
443
|
-
status.add_tcp_listener uri.host, uri.port
|
|
444
|
-
when "unix"
|
|
445
|
-
log "* Starting status server on #{str}"
|
|
446
|
-
path = "#{uri.host}#{uri.path}"
|
|
447
|
-
|
|
448
|
-
status.add_unix_listener path
|
|
449
|
-
else
|
|
450
|
-
error "Invalid status URI: #{str}"
|
|
82
|
+
def configure_control_url(command_line_arg)
|
|
83
|
+
if command_line_arg
|
|
84
|
+
@control_url = command_line_arg
|
|
85
|
+
elsif Puma.jruby?
|
|
86
|
+
unsupported "No default url available on JRuby"
|
|
451
87
|
end
|
|
452
|
-
|
|
453
|
-
status.run
|
|
454
|
-
@status = status
|
|
455
88
|
end
|
|
456
89
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if jruby_daemon?
|
|
461
|
-
require 'puma/jruby_restart'
|
|
462
|
-
|
|
463
|
-
if JRubyRestart.daemon?
|
|
464
|
-
# Bind before redirecting IO so binding errors show up on stdout/stderr
|
|
465
|
-
@binder.parse @options[:binds], self
|
|
466
|
-
end
|
|
467
|
-
|
|
468
|
-
already_daemon = JRubyRestart.daemon_init
|
|
469
|
-
end
|
|
470
|
-
|
|
471
|
-
output_header
|
|
472
|
-
|
|
473
|
-
if !jruby_daemon?
|
|
474
|
-
@binder.parse @options[:binds], self
|
|
475
|
-
end
|
|
476
|
-
|
|
477
|
-
unless @config.app_configured?
|
|
478
|
-
error "No application configured, nothing to run"
|
|
479
|
-
exit 1
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
# Load the app before we daemonize.
|
|
483
|
-
begin
|
|
484
|
-
app = @config.app
|
|
485
|
-
rescue Exception => e
|
|
486
|
-
log "! Unable to load application"
|
|
487
|
-
raise e
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
if jruby_daemon?
|
|
491
|
-
unless already_daemon
|
|
492
|
-
require 'puma/jruby_restart'
|
|
493
|
-
|
|
494
|
-
pid = nil
|
|
90
|
+
# Build the OptionParser object to handle the available options.
|
|
91
|
+
#
|
|
495
92
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
93
|
+
def setup_options(env = ENV)
|
|
94
|
+
@conf = Configuration.new({}, { events: @events }, env) do |user_config, file_config|
|
|
95
|
+
@parser = OptionParser.new do |o|
|
|
96
|
+
o.on "-b", "--bind URI", "URI to bind to (tcp://, unix://, ssl://)" do |arg|
|
|
97
|
+
user_config.bind arg
|
|
499
98
|
end
|
|
500
99
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
elsif daemon?
|
|
505
|
-
Process.daemon(true)
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
write_state
|
|
509
|
-
|
|
510
|
-
server = Puma::Server.new app, @events
|
|
511
|
-
server.binder = @binder
|
|
512
|
-
server.min_threads = @options[:min_threads]
|
|
513
|
-
server.max_threads = @options[:max_threads]
|
|
514
|
-
|
|
515
|
-
@server = server
|
|
516
|
-
|
|
517
|
-
if str = @options[:control_url]
|
|
518
|
-
start_control server, str
|
|
519
|
-
end
|
|
520
|
-
|
|
521
|
-
begin
|
|
522
|
-
Signal.trap "SIGUSR2" do
|
|
523
|
-
@restart = true
|
|
524
|
-
server.begin_restart
|
|
525
|
-
end
|
|
526
|
-
rescue Exception
|
|
527
|
-
log "*** Sorry signal SIGUSR2 not implemented, restart feature disabled!"
|
|
528
|
-
end
|
|
529
|
-
|
|
530
|
-
begin
|
|
531
|
-
Signal.trap "SIGTERM" do
|
|
532
|
-
log " - Gracefully stopping, waiting for requests to finish"
|
|
533
|
-
server.stop false
|
|
534
|
-
end
|
|
535
|
-
rescue Exception
|
|
536
|
-
log "*** Sorry signal SIGTERM not implemented, gracefully stopping feature disabled!"
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
unless @options[:daemon]
|
|
540
|
-
log "Use Ctrl-C to stop"
|
|
541
|
-
end
|
|
542
|
-
|
|
543
|
-
redirect_io
|
|
544
|
-
|
|
545
|
-
if jruby?
|
|
546
|
-
Signal.trap("INT") do
|
|
547
|
-
graceful_stop server
|
|
548
|
-
exit
|
|
549
|
-
end
|
|
550
|
-
end
|
|
551
|
-
|
|
552
|
-
begin
|
|
553
|
-
server.run.join
|
|
554
|
-
rescue Interrupt
|
|
555
|
-
graceful_stop server
|
|
556
|
-
end
|
|
557
|
-
|
|
558
|
-
if @restart
|
|
559
|
-
log "* Restarting..."
|
|
560
|
-
@status.stop true if @status
|
|
561
|
-
restart!
|
|
562
|
-
end
|
|
563
|
-
end
|
|
564
|
-
|
|
565
|
-
def worker(upgrade)
|
|
566
|
-
$0 = "puma: cluster worker: #{@master_pid}"
|
|
567
|
-
Signal.trap "SIGINT", "IGNORE"
|
|
568
|
-
|
|
569
|
-
@master_read.close
|
|
570
|
-
@suicide_pipe.close
|
|
571
|
-
|
|
572
|
-
Thread.new do
|
|
573
|
-
IO.select [@check_pipe]
|
|
574
|
-
log "! Detected parent died, dying"
|
|
575
|
-
exit! 1
|
|
576
|
-
end
|
|
577
|
-
|
|
578
|
-
# Be sure to change the directory again before loading
|
|
579
|
-
# the app. This way we can pick up new code.
|
|
580
|
-
if upgrade
|
|
581
|
-
if dir = @options[:worker_directory]
|
|
582
|
-
log "+ Changing to #{dir}"
|
|
583
|
-
Dir.chdir dir
|
|
584
|
-
end
|
|
585
|
-
end
|
|
586
|
-
|
|
587
|
-
# Invoke any worker boot hooks so they can get
|
|
588
|
-
# things in shape before booting the app.
|
|
589
|
-
hooks = @options[:worker_boot]
|
|
590
|
-
hooks.each { |h| h.call }
|
|
591
|
-
|
|
592
|
-
min_t = @options[:min_threads]
|
|
593
|
-
max_t = @options[:max_threads]
|
|
594
|
-
|
|
595
|
-
server = Puma::Server.new @config.app, @events
|
|
596
|
-
server.min_threads = min_t
|
|
597
|
-
server.max_threads = max_t
|
|
598
|
-
server.inherit_binder @binder
|
|
599
|
-
|
|
600
|
-
Signal.trap "SIGTERM" do
|
|
601
|
-
server.stop
|
|
602
|
-
end
|
|
603
|
-
|
|
604
|
-
begin
|
|
605
|
-
@worker_write << "b#{Process.pid}\n"
|
|
606
|
-
rescue SystemCallError, IOError
|
|
607
|
-
STDERR.puts "Master seems to have exitted, exitting."
|
|
608
|
-
return
|
|
609
|
-
end
|
|
610
|
-
|
|
611
|
-
server.run.join
|
|
612
|
-
|
|
613
|
-
ensure
|
|
614
|
-
@worker_write.close
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
def stop_workers
|
|
618
|
-
log "- Gracefully shutting down workers..."
|
|
619
|
-
@workers.each { |x| x.term }
|
|
620
|
-
|
|
621
|
-
begin
|
|
622
|
-
Process.waitall
|
|
623
|
-
rescue Interrupt
|
|
624
|
-
log "! Cancelled waiting for workers"
|
|
625
|
-
else
|
|
626
|
-
log "- Goodbye!"
|
|
627
|
-
end
|
|
628
|
-
end
|
|
629
|
-
|
|
630
|
-
def start_phased_restart
|
|
631
|
-
@phase += 1
|
|
632
|
-
log "- Starting phased worker restart, phase: #{@phase}"
|
|
633
|
-
end
|
|
634
|
-
|
|
635
|
-
class Worker
|
|
636
|
-
def initialize(pid, phase)
|
|
637
|
-
@pid = pid
|
|
638
|
-
@phase = phase
|
|
639
|
-
@stage = :started
|
|
640
|
-
end
|
|
641
|
-
|
|
642
|
-
attr_reader :pid, :phase
|
|
643
|
-
|
|
644
|
-
def booted?
|
|
645
|
-
@stage == :booted
|
|
646
|
-
end
|
|
647
|
-
|
|
648
|
-
def boot!
|
|
649
|
-
@stage = :booted
|
|
650
|
-
end
|
|
651
|
-
|
|
652
|
-
def term
|
|
653
|
-
begin
|
|
654
|
-
Process.kill "TERM", @pid
|
|
655
|
-
rescue Errno::ESRCH
|
|
656
|
-
end
|
|
657
|
-
end
|
|
658
|
-
end
|
|
659
|
-
|
|
660
|
-
def spawn_workers
|
|
661
|
-
diff = @options[:workers] - @workers.size
|
|
662
|
-
|
|
663
|
-
upgrade = (@phased_state == :waiting)
|
|
664
|
-
|
|
665
|
-
diff.times do
|
|
666
|
-
pid = fork { worker(upgrade) }
|
|
667
|
-
debug "Spawned worker: #{pid}"
|
|
668
|
-
@workers << Worker.new(pid, @phase)
|
|
669
|
-
end
|
|
100
|
+
o.on "--bind-to-activated-sockets [only]", "Bind to all activated sockets" do |arg|
|
|
101
|
+
user_config.bind_to_activated_sockets(arg || true)
|
|
102
|
+
end
|
|
670
103
|
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
end
|
|
104
|
+
o.on "-C", "--config PATH", "Load PATH as a config file" do |arg|
|
|
105
|
+
file_config.load arg
|
|
106
|
+
end
|
|
675
107
|
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
108
|
+
# Identical to supplying --config "-", but more semantic
|
|
109
|
+
o.on "--no-config", "Prevent Puma from searching for a config file" do |arg|
|
|
110
|
+
file_config.load "-"
|
|
111
|
+
end
|
|
679
112
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
break unless pid
|
|
113
|
+
o.on "--control-url URL", "The bind url to use for the control server. Use 'auto' to use temp unix server" do |arg|
|
|
114
|
+
configure_control_url(arg)
|
|
115
|
+
end
|
|
684
116
|
|
|
685
|
-
|
|
686
|
-
|
|
117
|
+
o.on "--control-token TOKEN",
|
|
118
|
+
"The token to use as authentication for the control server" do |arg|
|
|
119
|
+
@control_options[:auth_token] = arg
|
|
120
|
+
end
|
|
687
121
|
|
|
688
|
-
|
|
122
|
+
o.on "--debug", "Log lowlevel debugging information" do
|
|
123
|
+
user_config.debug
|
|
124
|
+
end
|
|
689
125
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
# in the right phase).
|
|
694
|
-
#
|
|
695
|
-
w = @workers.find { |x| x.phase != @phase }
|
|
126
|
+
o.on "--dir DIR", "Change to DIR before starting" do |d|
|
|
127
|
+
user_config.directory d
|
|
128
|
+
end
|
|
696
129
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
end
|
|
702
|
-
end
|
|
703
|
-
end
|
|
130
|
+
o.on "-e", "--environment ENVIRONMENT",
|
|
131
|
+
"The environment to run the Rack app on (default development)" do |arg|
|
|
132
|
+
user_config.environment arg
|
|
133
|
+
end
|
|
704
134
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
end
|
|
135
|
+
o.on "-f", "--fork-worker=[REQUESTS]", OptionParser::DecimalInteger,
|
|
136
|
+
"Fork new workers from existing worker. Cluster mode only",
|
|
137
|
+
"Auto-refork after REQUESTS (default 1000)" do |*args|
|
|
138
|
+
user_config.fork_worker(*args.compact)
|
|
139
|
+
end
|
|
711
140
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
log "* Min threads: #{@options[:min_threads]}, max threads: #{@options[:max_threads]}"
|
|
716
|
-
log "* Environment: #{ENV['RACK_ENV']}"
|
|
141
|
+
o.on "-I", "--include PATH", "Specify $LOAD_PATH directories" do |arg|
|
|
142
|
+
$LOAD_PATH.unshift(*arg.split(':'))
|
|
143
|
+
end
|
|
717
144
|
|
|
718
|
-
|
|
145
|
+
o.on "--idle-timeout SECONDS", "Number of seconds until the next request before automatic shutdown" do |arg|
|
|
146
|
+
user_config.idle_timeout arg
|
|
147
|
+
end
|
|
719
148
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
149
|
+
o.on "-p", "--port PORT", "Define the TCP port to bind to",
|
|
150
|
+
"Use -b for more advanced options" do |arg|
|
|
151
|
+
user_config.bind "tcp://#{Configuration::DEFAULTS[:tcp_host]}:#{arg}"
|
|
152
|
+
end
|
|
724
153
|
|
|
725
|
-
|
|
154
|
+
o.on "--pidfile PATH", "Use PATH as a pidfile" do |arg|
|
|
155
|
+
user_config.pidfile arg
|
|
156
|
+
end
|
|
726
157
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
158
|
+
o.on "--plugin PLUGIN", "Load the given PLUGIN. Can be used multiple times to load multiple plugins." do |arg|
|
|
159
|
+
user_config.plugin arg
|
|
160
|
+
end
|
|
730
161
|
|
|
731
|
-
|
|
162
|
+
o.on "--preload", "Preload the app. Cluster mode only" do
|
|
163
|
+
user_config.preload_app!
|
|
164
|
+
end
|
|
732
165
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
stop = true
|
|
737
|
-
wakeup!
|
|
738
|
-
end
|
|
739
|
-
rescue Exception
|
|
740
|
-
end
|
|
166
|
+
o.on "--prune-bundler", "Prune out the bundler env if possible" do
|
|
167
|
+
user_config.prune_bundler
|
|
168
|
+
end
|
|
741
169
|
|
|
742
|
-
|
|
170
|
+
o.on "--extra-runtime-dependencies GEM1,GEM2", "Defines any extra needed gems when using --prune-bundler" do |arg|
|
|
171
|
+
user_config.extra_runtime_dependencies arg.split(',')
|
|
172
|
+
end
|
|
743
173
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
# The worker installs their own SIGTERM when booted.
|
|
747
|
-
# Until then, this is run by the worker and the worker
|
|
748
|
-
# should just exit if they get it.
|
|
749
|
-
if Process.pid != master_pid
|
|
750
|
-
log "Early termination of worker"
|
|
751
|
-
exit! 0
|
|
752
|
-
else
|
|
753
|
-
stop = true
|
|
754
|
-
wakeup!
|
|
174
|
+
o.on "-q", "--quiet", "Do not log requests internally (default true)" do
|
|
175
|
+
user_config.quiet
|
|
755
176
|
end
|
|
756
|
-
end
|
|
757
|
-
rescue Exception
|
|
758
|
-
end
|
|
759
177
|
|
|
760
|
-
|
|
178
|
+
o.on "-v", "--log-requests", "Log requests as they occur" do
|
|
179
|
+
user_config.log_requests
|
|
180
|
+
end
|
|
761
181
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
rescue Exception
|
|
768
|
-
end
|
|
182
|
+
o.on "-R", "--restart-cmd CMD",
|
|
183
|
+
"The puma command to run during a hot restart",
|
|
184
|
+
"Default: inferred" do |cmd|
|
|
185
|
+
user_config.restart_command cmd
|
|
186
|
+
end
|
|
769
187
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
# closed.
|
|
774
|
-
#
|
|
775
|
-
@check_pipe, @suicide_pipe = Puma::Util.pipe
|
|
776
|
-
|
|
777
|
-
if @options[:daemon]
|
|
778
|
-
Process.daemon(true)
|
|
779
|
-
else
|
|
780
|
-
log "Use Ctrl-C to stop"
|
|
781
|
-
end
|
|
188
|
+
o.on "-s", "--silent", "Do not log prompt messages other than errors" do
|
|
189
|
+
@log_writer = LogWriter.new(NullIO.new, $stderr)
|
|
190
|
+
end
|
|
782
191
|
|
|
783
|
-
|
|
192
|
+
o.on "-S", "--state PATH", "Where to store the state details" do |arg|
|
|
193
|
+
user_config.state_path arg
|
|
194
|
+
end
|
|
784
195
|
|
|
785
|
-
|
|
196
|
+
o.on '-t', '--threads INT', "min:max threads to use (default 0:16)" do |arg|
|
|
197
|
+
min, max = arg.split(":")
|
|
198
|
+
if max
|
|
199
|
+
user_config.threads min, max
|
|
200
|
+
else
|
|
201
|
+
user_config.threads min, min
|
|
202
|
+
end
|
|
203
|
+
end
|
|
786
204
|
|
|
787
|
-
|
|
205
|
+
o.on "--early-hints", "Enable early hints support" do
|
|
206
|
+
user_config.early_hints
|
|
207
|
+
end
|
|
788
208
|
|
|
789
|
-
|
|
790
|
-
|
|
209
|
+
o.on "-V", "--version", "Print the version information" do
|
|
210
|
+
puts "puma version #{Puma::Const::VERSION}"
|
|
211
|
+
exit 0
|
|
212
|
+
end
|
|
791
213
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
214
|
+
o.on "-w", "--workers COUNT",
|
|
215
|
+
"Activate cluster mode: How many worker processes to create" do |arg|
|
|
216
|
+
user_config.workers arg
|
|
217
|
+
end
|
|
796
218
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
res = IO.select([read], nil, nil, 5)
|
|
801
|
-
|
|
802
|
-
if res
|
|
803
|
-
req = read.read_nonblock(1)
|
|
804
|
-
|
|
805
|
-
if req == "b"
|
|
806
|
-
pid = read.gets.to_i
|
|
807
|
-
w = @workers.find { |x| x.pid == pid }
|
|
808
|
-
if w
|
|
809
|
-
w.boot!
|
|
810
|
-
log "- Worker #{pid} booted, phase: #{w.phase}"
|
|
811
|
-
else
|
|
812
|
-
log "! Out-of-sync worker list, no #{pid} worker"
|
|
813
|
-
end
|
|
814
|
-
end
|
|
815
|
-
end
|
|
219
|
+
o.on "--tag NAME", "Additional text to display in process listing" do |arg|
|
|
220
|
+
user_config.tag arg
|
|
221
|
+
end
|
|
816
222
|
|
|
817
|
-
|
|
223
|
+
o.on "--redirect-stdout FILE", "Redirect STDOUT to a specific file" do |arg|
|
|
224
|
+
@stdout = arg.to_s
|
|
225
|
+
end
|
|
818
226
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
end
|
|
227
|
+
o.on "--redirect-stderr FILE", "Redirect STDERR to a specific file" do |arg|
|
|
228
|
+
@stderr = arg.to_s
|
|
229
|
+
end
|
|
823
230
|
|
|
824
|
-
|
|
825
|
-
|
|
231
|
+
o.on "--[no-]redirect-append", "Append to redirected files" do |val|
|
|
232
|
+
@append = val
|
|
826
233
|
end
|
|
827
|
-
end
|
|
828
234
|
|
|
829
|
-
|
|
830
|
-
ensure
|
|
831
|
-
delete_pidfile
|
|
832
|
-
@check_pipe.close
|
|
833
|
-
@suicide_pipe.close
|
|
834
|
-
read.close
|
|
835
|
-
@wakeup.close
|
|
836
|
-
end
|
|
235
|
+
o.banner = "puma <options> <rackup file>"
|
|
837
236
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
237
|
+
o.on_tail "-h", "--help", "Show help" do
|
|
238
|
+
$stdout.puts o
|
|
239
|
+
exit 0
|
|
240
|
+
end
|
|
241
|
+
end.parse! @argv
|
|
841
242
|
end
|
|
842
243
|
end
|
|
843
|
-
|
|
844
|
-
def stop
|
|
845
|
-
@status.stop(true) if @status
|
|
846
|
-
@server.stop(true) if @server
|
|
847
|
-
delete_pidfile
|
|
848
|
-
end
|
|
849
244
|
end
|
|
850
245
|
end
|