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.

Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +58 -31
  3. data/LICENSE +23 -20
  4. data/README.md +17 -11
  5. data/docs/deployment.md +3 -1
  6. data/docs/fork_worker.md +31 -0
  7. data/docs/jungle/README.md +13 -0
  8. data/{tools → docs}/jungle/rc.d/README.md +0 -0
  9. data/{tools → docs}/jungle/rc.d/puma +0 -0
  10. data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
  11. data/{tools → docs}/jungle/upstart/README.md +0 -0
  12. data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
  13. data/{tools → docs}/jungle/upstart/puma.conf +0 -0
  14. data/docs/signals.md +1 -0
  15. data/docs/systemd.md +1 -63
  16. data/ext/puma_http11/PumaHttp11Service.java +2 -4
  17. data/ext/puma_http11/extconf.rb +3 -2
  18. data/ext/puma_http11/http11_parser.c +11 -26
  19. data/ext/puma_http11/http11_parser.rl +1 -3
  20. data/ext/puma_http11/http11_parser_common.rl +1 -1
  21. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  22. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +46 -48
  23. data/ext/puma_http11/puma_http11.c +2 -38
  24. data/lib/puma/app/status.rb +16 -5
  25. data/lib/puma/binder.rb +62 -60
  26. data/lib/puma/cli.rb +7 -15
  27. data/lib/puma/client.rb +35 -32
  28. data/lib/puma/cluster.rb +179 -74
  29. data/lib/puma/configuration.rb +30 -42
  30. data/lib/puma/const.rb +2 -3
  31. data/lib/puma/control_cli.rb +27 -17
  32. data/lib/puma/detect.rb +8 -0
  33. data/lib/puma/dsl.rb +70 -34
  34. data/lib/puma/io_buffer.rb +9 -2
  35. data/lib/puma/jruby_restart.rb +0 -58
  36. data/lib/puma/launcher.rb +41 -29
  37. data/lib/puma/minissl.rb +13 -8
  38. data/lib/puma/null_io.rb +1 -1
  39. data/lib/puma/plugin.rb +1 -10
  40. data/lib/puma/rack/builder.rb +0 -4
  41. data/lib/puma/reactor.rb +6 -1
  42. data/lib/puma/runner.rb +5 -34
  43. data/lib/puma/server.rb +70 -190
  44. data/lib/puma/single.rb +7 -64
  45. data/lib/puma/state_file.rb +5 -2
  46. data/lib/puma/thread_pool.rb +85 -47
  47. data/lib/puma.rb +4 -0
  48. data/lib/rack/handler/puma.rb +1 -3
  49. data/tools/{docker/Dockerfile → Dockerfile} +0 -0
  50. metadata +22 -26
  51. data/docs/tcp_mode.md +0 -96
  52. data/ext/puma_http11/io_buffer.c +0 -155
  53. data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
  54. data/lib/puma/tcp_logger.rb +0 -41
  55. data/tools/jungle/README.md +0 -19
  56. data/tools/jungle/init.d/README.md +0 -61
  57. data/tools/jungle/init.d/puma +0 -421
  58. data/tools/jungle/init.d/run-puma +0 -18
@@ -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
- ).tap(&:connect)
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 == "stats" || @command == "gc-stats"
191
+ message response.last if PRINTABLE_COMMANDS.include?(@command)
191
192
  end
192
193
  ensure
193
- server.close if server && !server.closed?
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
- private
275
+ private
266
276
  def start
267
277
  require 'puma/cli'
268
278
 
data/lib/puma/detect.rb CHANGED
@@ -12,4 +12,12 @@ module Puma
12
12
  def self.windows?
13
13
  IS_WINDOWS
14
14
  end
15
+
16
+ def self.mri?
17
+ RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?
18
+ end
19
+
20
+ def self.forkable?
21
+ ::Process.respond_to?(:fork)
22
+ end
15
23
  end
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
- Integer(val)
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] = path.to_s
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
- # to the number of available cores.
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
@@ -1,4 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/detect'
4
- require 'puma/puma_http11'
3
+ module Puma
4
+ class IOBuffer < String
5
+ def append(*args)
6
+ args.each { |a| concat(a) }
7
+ end
8
+
9
+ alias reset clear
10
+ end
11
+ end
@@ -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.import_from_env
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
- @binder.close_unix_paths
185
+ close_binder_listeners unless @status == :restart
188
186
  end
189
187
 
190
- # Return which tcp port the launcher is using, if it's using TCP
191
- def connected_port
192
- @binder.connected_port
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.with_clean_env do
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
- Signal.trap "SIGINFO" do
460
- log_thread_status
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
- return :eof unless read_nonblock(1024)
129
- :drop
130
- rescue Errno::EAGAIN
131
- # do nothing
132
- :eagain
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
@@ -15,7 +15,7 @@ module Puma
15
15
  # Mimics IO#read with no data.
16
16
  #
17
17
  def read(count = nil, _buffer = nil)
18
- (count && count > 0) ? nil : ""
18
+ count && count > 0 ? nil : ""
19
19
  end
20
20
 
21
21
  def rewind
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(Plugin)
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
@@ -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.close
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
- case uri.scheme
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