puma 4.3.10 → 5.0.0.beta1
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.md +58 -31
- data/LICENSE +23 -20
- data/README.md +17 -11
- data/docs/deployment.md +3 -1
- data/docs/fork_worker.md +31 -0
- data/docs/jungle/README.md +13 -0
- data/{tools → docs}/jungle/rc.d/README.md +0 -0
- data/{tools → docs}/jungle/rc.d/puma +0 -0
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +0 -0
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -63
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/extconf.rb +3 -2
- data/ext/puma_http11/http11_parser.c +11 -26
- data/ext/puma_http11/http11_parser.rl +1 -3
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +46 -48
- data/ext/puma_http11/puma_http11.c +2 -38
- data/lib/puma/app/status.rb +16 -5
- data/lib/puma/binder.rb +62 -60
- data/lib/puma/cli.rb +7 -15
- data/lib/puma/client.rb +35 -32
- data/lib/puma/cluster.rb +179 -74
- data/lib/puma/configuration.rb +30 -42
- data/lib/puma/const.rb +2 -3
- data/lib/puma/control_cli.rb +27 -17
- data/lib/puma/detect.rb +8 -0
- data/lib/puma/dsl.rb +70 -34
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/launcher.rb +41 -29
- data/lib/puma/minissl.rb +13 -8
- data/lib/puma/null_io.rb +1 -1
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +6 -1
- data/lib/puma/runner.rb +5 -34
- data/lib/puma/server.rb +70 -190
- data/lib/puma/single.rb +7 -64
- data/lib/puma/state_file.rb +5 -2
- data/lib/puma/thread_pool.rb +85 -47
- data/lib/puma.rb +4 -0
- data/lib/rack/handler/puma.rb +1 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- metadata +22 -26
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
data/lib/puma/control_cli.rb
CHANGED
@@ -11,7 +11,8 @@ require 'socket'
|
|
11
11
|
module Puma
|
12
12
|
class ControlCLI
|
13
13
|
|
14
|
-
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
|
14
|
+
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats thread-backtraces refork}
|
15
|
+
PRINTABLE_COMMANDS = %w{gc-stats stats thread-backtraces}
|
15
16
|
|
16
17
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
17
18
|
@state = nil
|
@@ -22,7 +23,7 @@ module Puma
|
|
22
23
|
@control_auth_token = nil
|
23
24
|
@config_file = nil
|
24
25
|
@command = nil
|
25
|
-
@environment = ENV['RACK_ENV']
|
26
|
+
@environment = ENV['RACK_ENV'] || ENV['RAILS_ENV']
|
26
27
|
|
27
28
|
@argv = argv.dup
|
28
29
|
@stdout = stdout
|
@@ -81,6 +82,15 @@ module Puma
|
|
81
82
|
|
82
83
|
@command = argv.shift
|
83
84
|
|
85
|
+
# check presence of command
|
86
|
+
unless @command
|
87
|
+
raise "Available commands: #{COMMANDS.join(", ")}"
|
88
|
+
end
|
89
|
+
|
90
|
+
unless COMMANDS.include? @command
|
91
|
+
raise "Invalid command: #{@command}"
|
92
|
+
end
|
93
|
+
|
84
94
|
unless @config_file == '-'
|
85
95
|
environment = @environment || 'development'
|
86
96
|
|
@@ -99,16 +109,6 @@ module Puma
|
|
99
109
|
@pidfile ||= config.options[:pidfile]
|
100
110
|
end
|
101
111
|
end
|
102
|
-
|
103
|
-
# check present of command
|
104
|
-
unless @command
|
105
|
-
raise "Available commands: #{COMMANDS.join(", ")}"
|
106
|
-
end
|
107
|
-
|
108
|
-
unless COMMANDS.include? @command
|
109
|
-
raise "Invalid command: #{@command}"
|
110
|
-
end
|
111
|
-
|
112
112
|
rescue => e
|
113
113
|
@stdout.puts e.message
|
114
114
|
exit 1
|
@@ -145,8 +145,9 @@ module Puma
|
|
145
145
|
require 'openssl'
|
146
146
|
OpenSSL::SSL::SSLSocket.new(
|
147
147
|
TCPSocket.new(uri.host, uri.port),
|
148
|
-
OpenSSL::SSL::SSLContext.new
|
149
|
-
|
148
|
+
OpenSSL::SSL::SSLContext.new)
|
149
|
+
.tap { |ssl| ssl.sync_close = true } # default is false
|
150
|
+
.tap(&:connect)
|
150
151
|
when "tcp"
|
151
152
|
TCPSocket.new uri.host, uri.port
|
152
153
|
when "unix"
|
@@ -187,10 +188,16 @@ module Puma
|
|
187
188
|
end
|
188
189
|
|
189
190
|
message "Command #{@command} sent success"
|
190
|
-
message response.last if @command
|
191
|
+
message response.last if PRINTABLE_COMMANDS.include?(@command)
|
191
192
|
end
|
192
193
|
ensure
|
193
|
-
|
194
|
+
if server
|
195
|
+
if uri.scheme == "ssl"
|
196
|
+
server.sysclose
|
197
|
+
else
|
198
|
+
server.close unless server.closed?
|
199
|
+
end
|
200
|
+
end
|
194
201
|
end
|
195
202
|
|
196
203
|
def send_signal
|
@@ -231,6 +238,9 @@ module Puma
|
|
231
238
|
|
232
239
|
return
|
233
240
|
|
241
|
+
when "refork"
|
242
|
+
Process.kill "SIGURG", @pid
|
243
|
+
|
234
244
|
else
|
235
245
|
return
|
236
246
|
end
|
@@ -262,7 +272,7 @@ module Puma
|
|
262
272
|
exit 1
|
263
273
|
end
|
264
274
|
|
265
|
-
|
275
|
+
private
|
266
276
|
def start
|
267
277
|
require 'puma/cli'
|
268
278
|
|
data/lib/puma/detect.rb
CHANGED
data/lib/puma/dsl.rb
CHANGED
@@ -210,20 +210,6 @@ module Puma
|
|
210
210
|
@options[:clean_thread_locals] = which
|
211
211
|
end
|
212
212
|
|
213
|
-
# Daemonize the server into the background. It's highly recommended to
|
214
|
-
# use this in combination with +pidfile+ and +stdout_redirect+.
|
215
|
-
#
|
216
|
-
# The default is "false".
|
217
|
-
#
|
218
|
-
# @example
|
219
|
-
# daemonize
|
220
|
-
#
|
221
|
-
# @example
|
222
|
-
# daemonize false
|
223
|
-
def daemonize(which=true)
|
224
|
-
@options[:daemon] = which
|
225
|
-
end
|
226
|
-
|
227
213
|
# When shutting down, drain the accept socket of pending
|
228
214
|
# connections and process them. This loops over the accept
|
229
215
|
# socket until there are no more read events and then stops
|
@@ -257,7 +243,7 @@ module Puma
|
|
257
243
|
when :immediately
|
258
244
|
0
|
259
245
|
else
|
260
|
-
|
246
|
+
Float(val)
|
261
247
|
end
|
262
248
|
|
263
249
|
@options[:force_shutdown_after] = i
|
@@ -322,13 +308,7 @@ module Puma
|
|
322
308
|
# @example
|
323
309
|
# rackup '/u/apps/lolcat/config.ru'
|
324
310
|
def rackup(path)
|
325
|
-
@options[:rackup]
|
326
|
-
end
|
327
|
-
|
328
|
-
# Run Puma in TCP mode
|
329
|
-
#
|
330
|
-
def tcp_mode!
|
331
|
-
@options[:mode] = :tcp
|
311
|
+
@options[:rackup] ||= path.to_s
|
332
312
|
end
|
333
313
|
|
334
314
|
def early_hints(answer=true)
|
@@ -419,8 +399,16 @@ module Puma
|
|
419
399
|
@options[:state] = path.to_s
|
420
400
|
end
|
421
401
|
|
402
|
+
# Use +permission+ to restrict permissions for the state file.
|
403
|
+
#
|
404
|
+
# @example
|
405
|
+
# state_permission 0600
|
406
|
+
def state_permission(permission)
|
407
|
+
@options[:state_permission] = permission
|
408
|
+
end
|
409
|
+
|
422
410
|
# How many worker processes to run. Typically this is set to
|
423
|
-
#
|
411
|
+
# the number of available cores.
|
424
412
|
#
|
425
413
|
# The default is 0.
|
426
414
|
#
|
@@ -512,6 +500,28 @@ module Puma
|
|
512
500
|
|
513
501
|
alias_method :after_worker_boot, :after_worker_fork
|
514
502
|
|
503
|
+
# When `fork_worker` is enabled, code to run in Worker 0
|
504
|
+
# before all other workers are re-forked from this process,
|
505
|
+
# after the server has temporarily stopped serving requests
|
506
|
+
# (once per complete refork cycle).
|
507
|
+
#
|
508
|
+
# This can be used to trigger extra garbage-collection to maximize
|
509
|
+
# copy-on-write efficiency, or close any connections to remote servers
|
510
|
+
# (database, Redis, ...) that were opened while the server was running.
|
511
|
+
#
|
512
|
+
# This can be called multiple times to add several hooks.
|
513
|
+
#
|
514
|
+
# @note Cluster mode with `fork_worker` enabled only.
|
515
|
+
# @example
|
516
|
+
# on_refork do
|
517
|
+
# 3.times {GC.start}
|
518
|
+
# end
|
519
|
+
|
520
|
+
def on_refork(&block)
|
521
|
+
@options[:before_refork] ||= []
|
522
|
+
@options[:before_refork] << block
|
523
|
+
end
|
524
|
+
|
515
525
|
# Code to run out-of-band when the worker is idle.
|
516
526
|
# These hooks run immediately after a request has finished
|
517
527
|
# processing and there are no busy threads on the worker.
|
@@ -536,17 +546,6 @@ module Puma
|
|
536
546
|
@options[:directory] = dir.to_s
|
537
547
|
end
|
538
548
|
|
539
|
-
# DEPRECATED: The directory to operate out of.
|
540
|
-
def worker_directory(dir)
|
541
|
-
$stderr.puts "worker_directory is deprecated. Please use `directory`"
|
542
|
-
directory dir
|
543
|
-
end
|
544
|
-
|
545
|
-
# Run the app as a raw TCP app instead of an HTTP rack app.
|
546
|
-
def tcp_mode
|
547
|
-
@options[:mode] = :tcp
|
548
|
-
end
|
549
|
-
|
550
549
|
# Preload the application before starting the workers; this conflicts with
|
551
550
|
# phased restart feature. This is off by default.
|
552
551
|
#
|
@@ -695,6 +694,16 @@ module Puma
|
|
695
694
|
@options[:shutdown_debug] = val
|
696
695
|
end
|
697
696
|
|
697
|
+
|
698
|
+
# Attempts to route traffic to less-busy workers by causing them to delay
|
699
|
+
# listening on the socket, allowing workers which are not processing any
|
700
|
+
# requests to pick up new requests first.
|
701
|
+
#
|
702
|
+
# Only works on MRI. For all other interpreters, this setting does nothing.
|
703
|
+
def wait_for_less_busy_worker(val=0.005)
|
704
|
+
@options[:wait_for_less_busy_worker] = val.to_f
|
705
|
+
end
|
706
|
+
|
698
707
|
# Control how the remote address of the connection is set. This
|
699
708
|
# is configurable because to calculate the true socket peer address
|
700
709
|
# a kernel syscall is required which for very fast rack handlers
|
@@ -736,5 +745,32 @@ module Puma
|
|
736
745
|
end
|
737
746
|
end
|
738
747
|
|
748
|
+
# When enabled, workers will be forked from worker 0 instead of from the master process.
|
749
|
+
# This option is similar to `preload_app` because the app is preloaded before forking,
|
750
|
+
# but it is compatible with phased restart.
|
751
|
+
#
|
752
|
+
# This option also enables the `refork` command (SIGURG), which optimizes copy-on-write performance
|
753
|
+
# in a running app.
|
754
|
+
#
|
755
|
+
# A refork will automatically trigger once after the specified number of requests
|
756
|
+
# (default 1000), or pass 0 to disable auto refork.
|
757
|
+
#
|
758
|
+
# @note Cluster mode only.
|
759
|
+
def fork_worker(after_requests=1000)
|
760
|
+
@options[:fork_worker] = Integer(after_requests)
|
761
|
+
end
|
762
|
+
|
763
|
+
# When enabled, Puma will GC 4 times before forking workers.
|
764
|
+
# If available (Ruby 2.7+), we will also call GC.compact.
|
765
|
+
# Not recommended for non-MRI Rubies.
|
766
|
+
#
|
767
|
+
# Based on the work of Koichi Sasada and Aaron Patterson, this option may
|
768
|
+
# decrease memory utilization of preload-enabled cluster-mode Pumas. It will
|
769
|
+
# also increase time to boot and fork. See your logs for details on how much
|
770
|
+
# time this adds to your boot process. For most apps, it will be less than one
|
771
|
+
# second.
|
772
|
+
def nakayoshi_fork(enabled=false)
|
773
|
+
@options[:nakayoshi_fork] = enabled
|
774
|
+
end
|
739
775
|
end
|
740
776
|
end
|
data/lib/puma/io_buffer.rb
CHANGED
data/lib/puma/jruby_restart.rb
CHANGED
@@ -22,63 +22,5 @@ module Puma
|
|
22
22
|
execlp(cmd, *argv)
|
23
23
|
raise SystemCallError.new(FFI.errno)
|
24
24
|
end
|
25
|
-
|
26
|
-
PermKey = 'PUMA_DAEMON_PERM'
|
27
|
-
RestartKey = 'PUMA_DAEMON_RESTART'
|
28
|
-
|
29
|
-
# Called to tell things "Your now always in daemon mode,
|
30
|
-
# don't try to reenter it."
|
31
|
-
#
|
32
|
-
def self.perm_daemonize
|
33
|
-
ENV[PermKey] = "1"
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.daemon?
|
37
|
-
ENV.key?(PermKey) || ENV.key?(RestartKey)
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.daemon_init
|
41
|
-
return true if ENV.key?(PermKey)
|
42
|
-
|
43
|
-
return false unless ENV.key? RestartKey
|
44
|
-
|
45
|
-
master = ENV[RestartKey]
|
46
|
-
|
47
|
-
# In case the master disappears early
|
48
|
-
begin
|
49
|
-
Process.kill "SIGUSR2", master.to_i
|
50
|
-
rescue SystemCallError => e
|
51
|
-
end
|
52
|
-
|
53
|
-
ENV[RestartKey] = ""
|
54
|
-
|
55
|
-
setsid
|
56
|
-
|
57
|
-
null = File.open "/dev/null", "w+"
|
58
|
-
STDIN.reopen null
|
59
|
-
STDOUT.reopen null
|
60
|
-
STDERR.reopen null
|
61
|
-
|
62
|
-
true
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.daemon_start(dir, argv)
|
66
|
-
ENV[RestartKey] = Process.pid.to_s
|
67
|
-
|
68
|
-
if k = ENV['PUMA_JRUBY_DAEMON_OPTS']
|
69
|
-
ENV['JRUBY_OPTS'] = k
|
70
|
-
end
|
71
|
-
|
72
|
-
cmd = argv.first
|
73
|
-
argv = ([:string] * argv.size).zip(argv).flatten
|
74
|
-
argv << :string
|
75
|
-
argv << nil
|
76
|
-
|
77
|
-
chdir(dir)
|
78
|
-
ret = fork
|
79
|
-
return ret if ret != 0
|
80
|
-
execlp(cmd, *argv)
|
81
|
-
raise SystemCallError.new(FFI.errno)
|
82
|
-
end
|
83
25
|
end
|
84
26
|
end
|
data/lib/puma/launcher.rb
CHANGED
@@ -48,7 +48,8 @@ module Puma
|
|
48
48
|
@config = conf
|
49
49
|
|
50
50
|
@binder = Binder.new(@events)
|
51
|
-
@binder.
|
51
|
+
@binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
|
52
|
+
@binder.create_activated_fds(ENV).each { |k| ENV.delete k }
|
52
53
|
|
53
54
|
@environment = conf.environment
|
54
55
|
|
@@ -69,10 +70,6 @@ module Puma
|
|
69
70
|
unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
|
70
71
|
end
|
71
72
|
|
72
|
-
if @options[:daemon] && Puma.windows?
|
73
|
-
unsupported 'daemon mode not supported on Windows'
|
74
|
-
end
|
75
|
-
|
76
73
|
Dir.chdir(@restart_dir)
|
77
74
|
|
78
75
|
prune_bundler if prune_bundler?
|
@@ -105,6 +102,7 @@ module Puma
|
|
105
102
|
write_pid
|
106
103
|
|
107
104
|
path = @options[:state]
|
105
|
+
permission = @options[:state_permission]
|
108
106
|
return unless path
|
109
107
|
|
110
108
|
require 'puma/state_file'
|
@@ -114,7 +112,7 @@ module Puma
|
|
114
112
|
sf.control_url = @options[:control_url]
|
115
113
|
sf.control_auth_token = @options[:control_auth_token]
|
116
114
|
|
117
|
-
sf.save path
|
115
|
+
sf.save path, permission
|
118
116
|
end
|
119
117
|
|
120
118
|
# Delete the configured pidfile
|
@@ -184,12 +182,12 @@ module Puma
|
|
184
182
|
when :exit
|
185
183
|
# nothing
|
186
184
|
end
|
187
|
-
@
|
185
|
+
close_binder_listeners unless @status == :restart
|
188
186
|
end
|
189
187
|
|
190
|
-
# Return
|
191
|
-
def
|
192
|
-
@binder.
|
188
|
+
# Return all tcp ports the launcher may be using, TCP or SSL
|
189
|
+
def connected_ports
|
190
|
+
@binder.connected_ports
|
193
191
|
end
|
194
192
|
|
195
193
|
def restart_args
|
@@ -202,9 +200,21 @@ module Puma
|
|
202
200
|
end
|
203
201
|
|
204
202
|
def close_binder_listeners
|
203
|
+
@runner.close_control_listeners
|
205
204
|
@binder.close_listeners
|
206
205
|
end
|
207
206
|
|
207
|
+
def thread_status
|
208
|
+
Thread.list.each do |thread|
|
209
|
+
name = "Thread: TID-#{thread.object_id.to_s(36)}"
|
210
|
+
name += " #{thread['label']}" if thread['label']
|
211
|
+
name += " #{thread.name}" if thread.respond_to?(:name) && thread.name
|
212
|
+
backtrace = thread.backtrace || ["<no backtrace available>"]
|
213
|
+
|
214
|
+
yield name, backtrace
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
208
218
|
private
|
209
219
|
|
210
220
|
# If configured, write the pid of the current process out
|
@@ -225,7 +235,7 @@ module Puma
|
|
225
235
|
end
|
226
236
|
|
227
237
|
def restart!
|
228
|
-
@config.run_hooks :on_restart, self
|
238
|
+
@config.run_hooks :on_restart, self, @events
|
229
239
|
|
230
240
|
if Puma.jruby?
|
231
241
|
close_binder_listeners
|
@@ -241,6 +251,7 @@ module Puma
|
|
241
251
|
else
|
242
252
|
argv = restart_args
|
243
253
|
Dir.chdir(@restart_dir)
|
254
|
+
ENV.update(@binder.redirects_for_restart_env)
|
244
255
|
argv += [@binder.redirects_for_restart]
|
245
256
|
Kernel.exec(*argv)
|
246
257
|
end
|
@@ -286,8 +297,10 @@ module Puma
|
|
286
297
|
|
287
298
|
log '* Pruning Bundler environment'
|
288
299
|
home = ENV['GEM_HOME']
|
289
|
-
Bundler.
|
300
|
+
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
301
|
+
with_unbundled_env do
|
290
302
|
ENV['GEM_HOME'] = home
|
303
|
+
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
291
304
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
292
305
|
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':'), deps.join(',')] + @original_argv
|
293
306
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
@@ -323,21 +336,6 @@ module Puma
|
|
323
336
|
log "- Goodbye!"
|
324
337
|
end
|
325
338
|
|
326
|
-
def log_thread_status
|
327
|
-
Thread.list.each do |thread|
|
328
|
-
log "Thread TID-#{thread.object_id.to_s(36)} #{thread['label']}"
|
329
|
-
logstr = "Thread: TID-#{thread.object_id.to_s(36)}"
|
330
|
-
logstr += " #{thread.name}" if thread.respond_to?(:name)
|
331
|
-
log logstr
|
332
|
-
|
333
|
-
if thread.backtrace
|
334
|
-
log thread.backtrace.join("\n")
|
335
|
-
else
|
336
|
-
log "<no backtrace available>"
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
339
|
def set_process_title
|
342
340
|
Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
|
343
341
|
end
|
@@ -456,8 +454,13 @@ module Puma
|
|
456
454
|
end
|
457
455
|
|
458
456
|
begin
|
459
|
-
|
460
|
-
|
457
|
+
unless Puma.jruby? # INFO in use by JVM already
|
458
|
+
Signal.trap "SIGINFO" do
|
459
|
+
thread_status do |name, backtrace|
|
460
|
+
@events.log name
|
461
|
+
@events.log backtrace.map { |bt| " #{bt}" }
|
462
|
+
end
|
463
|
+
end
|
461
464
|
end
|
462
465
|
rescue Exception
|
463
466
|
# Not going to log this one, as SIGINFO is *BSD only and would be pretty annoying
|
@@ -471,5 +474,14 @@ module Puma
|
|
471
474
|
raise "#{feature} is not supported on your version of RubyGems. " \
|
472
475
|
"You must have RubyGems #{min_version}+ to use this feature."
|
473
476
|
end
|
477
|
+
|
478
|
+
def with_unbundled_env
|
479
|
+
bundler_ver = Gem::Version.new(Bundler::VERSION)
|
480
|
+
if bundler_ver < Gem::Version.new('2.1.0')
|
481
|
+
Bundler.with_clean_env { yield }
|
482
|
+
else
|
483
|
+
Bundler.with_unbundled_env { yield }
|
484
|
+
end
|
485
|
+
end
|
474
486
|
end
|
475
487
|
end
|
data/lib/puma/minissl.rb
CHANGED
@@ -125,11 +125,14 @@ module Puma
|
|
125
125
|
|
126
126
|
def read_and_drop(timeout = 1)
|
127
127
|
return :timeout unless IO.select([@socket], nil, nil, timeout)
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
128
|
+
case @socket.read_nonblock(1024, exception: false)
|
129
|
+
when nil
|
130
|
+
:eof
|
131
|
+
when :wait_readable
|
132
|
+
:eagain
|
133
|
+
else
|
134
|
+
:drop
|
135
|
+
end
|
133
136
|
end
|
134
137
|
|
135
138
|
def should_drop_bytes?
|
@@ -141,9 +144,7 @@ module Puma
|
|
141
144
|
# Read any drop any partially initialized sockets and any received bytes during shutdown.
|
142
145
|
# Don't let this socket hold this loop forever.
|
143
146
|
# If it can't send more packets within 1s, then give up.
|
144
|
-
while should_drop_bytes?
|
145
|
-
return if [:timeout, :eof].include?(read_and_drop(1))
|
146
|
-
end
|
147
|
+
return if [:timeout, :eof].include?(read_and_drop(1)) while should_drop_bytes?
|
147
148
|
rescue IOError, SystemCallError
|
148
149
|
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
149
150
|
# nothing
|
@@ -270,6 +271,10 @@ module Puma
|
|
270
271
|
Socket.new io, engine
|
271
272
|
end
|
272
273
|
|
274
|
+
def addr
|
275
|
+
@socket.addr
|
276
|
+
end
|
277
|
+
|
273
278
|
def close
|
274
279
|
@socket.close unless @socket.closed? # closed? call is for Windows
|
275
280
|
end
|
data/lib/puma/null_io.rb
CHANGED
data/lib/puma/plugin.rb
CHANGED
@@ -10,7 +10,7 @@ module Puma
|
|
10
10
|
|
11
11
|
def create(name)
|
12
12
|
if cls = Plugins.find(name)
|
13
|
-
plugin = cls.new
|
13
|
+
plugin = cls.new
|
14
14
|
@instances << plugin
|
15
15
|
return plugin
|
16
16
|
end
|
@@ -104,17 +104,8 @@ module Puma
|
|
104
104
|
Plugins.register name, cls
|
105
105
|
end
|
106
106
|
|
107
|
-
def initialize(loader)
|
108
|
-
@loader = loader
|
109
|
-
end
|
110
|
-
|
111
107
|
def in_background(&blk)
|
112
108
|
Plugins.add_background blk
|
113
109
|
end
|
114
|
-
|
115
|
-
def workers_supported?
|
116
|
-
return false if Puma.jruby? || Puma.windows?
|
117
|
-
true
|
118
|
-
end
|
119
110
|
end
|
120
111
|
end
|
data/lib/puma/rack/builder.rb
CHANGED
@@ -67,10 +67,6 @@ module Puma::Rack
|
|
67
67
|
options[:environment] = e
|
68
68
|
}
|
69
69
|
|
70
|
-
opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
|
71
|
-
options[:daemonize] = d ? true : false
|
72
|
-
}
|
73
|
-
|
74
70
|
opts.on("-P", "--pid FILE", "file to store PID") { |f|
|
75
71
|
options[:pid] = ::File.expand_path(f)
|
76
72
|
}
|
data/lib/puma/reactor.rb
CHANGED
@@ -189,7 +189,12 @@ module Puma
|
|
189
189
|
if submon.value == @ready
|
190
190
|
false
|
191
191
|
else
|
192
|
-
submon.value.
|
192
|
+
if submon.value.can_close?
|
193
|
+
submon.value.close
|
194
|
+
else
|
195
|
+
# Pass remaining open client connections to the thread pool.
|
196
|
+
@app_pool << submon.value
|
197
|
+
end
|
193
198
|
begin
|
194
199
|
selector.deregister submon.value
|
195
200
|
rescue IOError
|
data/lib/puma/runner.rb
CHANGED
@@ -18,10 +18,6 @@ module Puma
|
|
18
18
|
@started_at = Time.now
|
19
19
|
end
|
20
20
|
|
21
|
-
def daemon?
|
22
|
-
@options[:daemon]
|
23
|
-
end
|
24
|
-
|
25
21
|
def development?
|
26
22
|
@options[:environment] == "development"
|
27
23
|
end
|
@@ -52,8 +48,6 @@ module Puma
|
|
52
48
|
|
53
49
|
require 'puma/app/status'
|
54
50
|
|
55
|
-
uri = URI.parse str
|
56
|
-
|
57
51
|
if token = @options[:control_auth_token]
|
58
52
|
token = nil if token.empty? || token == 'none'
|
59
53
|
end
|
@@ -64,30 +58,16 @@ module Puma
|
|
64
58
|
control.min_threads = 0
|
65
59
|
control.max_threads = 1
|
66
60
|
|
67
|
-
|
68
|
-
when "ssl"
|
69
|
-
log "* Starting control server on #{str}"
|
70
|
-
params = Util.parse_query uri.query
|
71
|
-
ctx = MiniSSL::ContextBuilder.new(params, @events).context
|
72
|
-
|
73
|
-
control.add_ssl_listener uri.host, uri.port, ctx
|
74
|
-
when "tcp"
|
75
|
-
log "* Starting control server on #{str}"
|
76
|
-
control.add_tcp_listener uri.host, uri.port
|
77
|
-
when "unix"
|
78
|
-
log "* Starting control server on #{str}"
|
79
|
-
path = "#{uri.host}#{uri.path}"
|
80
|
-
mask = @options[:control_url_umask]
|
81
|
-
|
82
|
-
control.add_unix_listener path, mask
|
83
|
-
else
|
84
|
-
error "Invalid control URI: #{str}"
|
85
|
-
end
|
61
|
+
control.binder.parse [str], self, 'Starting control server'
|
86
62
|
|
87
63
|
control.run
|
88
64
|
@control = control
|
89
65
|
end
|
90
66
|
|
67
|
+
def close_control_listeners
|
68
|
+
@control.binder.close_listeners if @control
|
69
|
+
end
|
70
|
+
|
91
71
|
def ruby_engine
|
92
72
|
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby"
|
93
73
|
"ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}"
|
@@ -108,10 +88,6 @@ module Puma
|
|
108
88
|
log "* Version #{Puma::Const::PUMA_VERSION} (#{ruby_engine}), codename: #{Puma::Const::CODE_NAME}"
|
109
89
|
log "* Min threads: #{min_t}, max threads: #{max_t}"
|
110
90
|
log "* Environment: #{ENV['RACK_ENV']}"
|
111
|
-
|
112
|
-
if @options[:mode] == :tcp
|
113
|
-
log "* Mode: Lopez Express (tcp)"
|
114
|
-
end
|
115
91
|
end
|
116
92
|
|
117
93
|
def redirected_io?
|
@@ -150,7 +126,6 @@ module Puma
|
|
150
126
|
exit 1
|
151
127
|
end
|
152
128
|
|
153
|
-
# Load the app before we daemonize.
|
154
129
|
begin
|
155
130
|
@app = @launcher.config.app
|
156
131
|
rescue Exception => e
|
@@ -174,10 +149,6 @@ module Puma
|
|
174
149
|
server.max_threads = max_t
|
175
150
|
server.inherit_binder @launcher.binder
|
176
151
|
|
177
|
-
if @options[:mode] == :tcp
|
178
|
-
server.tcp_mode!
|
179
|
-
end
|
180
|
-
|
181
152
|
if @options[:early_hints]
|
182
153
|
server.early_hints = true
|
183
154
|
end
|