puma 6.4.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 +4 -4
- data/History.md +407 -8
- data/README.md +109 -49
- data/docs/deployment.md +58 -23
- data/docs/fork_worker.md +11 -1
- data/docs/java_options.md +54 -0
- data/docs/jungle/README.md +1 -1
- data/docs/kubernetes.md +11 -16
- data/docs/plugins.md +6 -2
- data/docs/restart.md +2 -2
- data/docs/signals.md +21 -21
- data/docs/stats.md +11 -5
- data/docs/systemd.md +14 -5
- data/ext/puma_http11/extconf.rb +20 -32
- data/ext/puma_http11/mini_ssl.c +29 -9
- data/ext/puma_http11/org/jruby/puma/Http11.java +40 -9
- data/ext/puma_http11/puma_http11.c +125 -118
- data/lib/puma/app/status.rb +11 -3
- data/lib/puma/binder.rb +21 -11
- data/lib/puma/cli.rb +10 -8
- data/lib/puma/client.rb +183 -83
- data/lib/puma/cluster/worker.rb +24 -21
- data/lib/puma/cluster/worker_handle.rb +38 -8
- data/lib/puma/cluster.rb +73 -47
- data/lib/puma/cluster_accept_loop_delay.rb +91 -0
- data/lib/puma/commonlogger.rb +3 -3
- data/lib/puma/configuration.rb +131 -60
- data/lib/puma/const.rb +31 -12
- data/lib/puma/control_cli.rb +10 -6
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +411 -121
- data/lib/puma/error_logger.rb +7 -5
- data/lib/puma/events.rb +25 -10
- data/lib/puma/io_buffer.rb +8 -4
- data/lib/puma/jruby_restart.rb +0 -16
- data/lib/puma/launcher/bundle_pruner.rb +1 -1
- data/lib/puma/launcher.rb +73 -55
- data/lib/puma/log_writer.rb +9 -9
- data/lib/puma/minissl/context_builder.rb +1 -0
- data/lib/puma/minissl.rb +1 -1
- data/lib/puma/null_io.rb +26 -0
- data/lib/puma/plugin/systemd.rb +3 -3
- data/lib/puma/rack/urlmap.rb +1 -1
- data/lib/puma/reactor.rb +19 -13
- data/lib/puma/request.rb +71 -39
- data/lib/puma/runner.rb +15 -17
- data/lib/puma/sd_notify.rb +1 -4
- data/lib/puma/server.rb +134 -73
- data/lib/puma/single.rb +7 -4
- data/lib/puma/state_file.rb +3 -2
- data/lib/puma/thread_pool.rb +57 -80
- data/lib/puma/util.rb +0 -7
- data/lib/puma.rb +10 -0
- data/lib/rack/handler/puma.rb +10 -7
- data/tools/Dockerfile +15 -5
- metadata +14 -15
- data/ext/puma_http11/ext_help.h +0 -15
data/lib/puma/server.rb
CHANGED
|
@@ -12,12 +12,13 @@ require_relative 'client'
|
|
|
12
12
|
require_relative 'binder'
|
|
13
13
|
require_relative 'util'
|
|
14
14
|
require_relative 'request'
|
|
15
|
+
require_relative 'configuration'
|
|
16
|
+
require_relative 'cluster_accept_loop_delay'
|
|
15
17
|
|
|
16
18
|
require 'socket'
|
|
17
19
|
require 'io/wait' unless Puma::HAS_NATIVE_IO_WAIT
|
|
18
20
|
|
|
19
21
|
module Puma
|
|
20
|
-
|
|
21
22
|
# The HTTP Server itself. Serves out a single Rack app.
|
|
22
23
|
#
|
|
23
24
|
# This class is used by the `Puma::Single` and `Puma::Cluster` classes
|
|
@@ -29,9 +30,18 @@ module Puma
|
|
|
29
30
|
#
|
|
30
31
|
# Each `Puma::Server` will have one reactor and one thread pool.
|
|
31
32
|
class Server
|
|
33
|
+
module FiberPerRequest
|
|
34
|
+
def handle_request(client, requests)
|
|
35
|
+
Fiber.new do
|
|
36
|
+
super
|
|
37
|
+
end.resume
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
32
41
|
include Puma::Const
|
|
33
42
|
include Request
|
|
34
43
|
|
|
44
|
+
attr_reader :options
|
|
35
45
|
attr_reader :thread
|
|
36
46
|
attr_reader :log_writer
|
|
37
47
|
attr_reader :events
|
|
@@ -46,8 +56,6 @@ module Puma
|
|
|
46
56
|
attr_accessor :app
|
|
47
57
|
attr_accessor :binder
|
|
48
58
|
|
|
49
|
-
THREAD_LOCAL_KEY = :puma_server
|
|
50
|
-
|
|
51
59
|
# Create a server for the rack app +app+.
|
|
52
60
|
#
|
|
53
61
|
# +log_writer+ is a Puma::LogWriter object used to log info and error messages.
|
|
@@ -74,6 +82,9 @@ module Puma
|
|
|
74
82
|
|
|
75
83
|
@thread = nil
|
|
76
84
|
@thread_pool = nil
|
|
85
|
+
@reactor = nil
|
|
86
|
+
|
|
87
|
+
@env_set_http_version = nil
|
|
77
88
|
|
|
78
89
|
@options = if options.is_a?(UserFileDefaultOptions)
|
|
79
90
|
options
|
|
@@ -91,9 +102,19 @@ module Puma
|
|
|
91
102
|
@min_threads = @options[:min_threads]
|
|
92
103
|
@max_threads = @options[:max_threads]
|
|
93
104
|
@queue_requests = @options[:queue_requests]
|
|
94
|
-
@
|
|
105
|
+
@max_keep_alive = @options[:max_keep_alive]
|
|
106
|
+
@enable_keep_alives = @options[:enable_keep_alives]
|
|
107
|
+
@enable_keep_alives &&= @queue_requests
|
|
95
108
|
@io_selector_backend = @options[:io_selector_backend]
|
|
96
109
|
@http_content_length_limit = @options[:http_content_length_limit]
|
|
110
|
+
@cluster_accept_loop_delay = ClusterAcceptLoopDelay.new(
|
|
111
|
+
workers: @options[:workers],
|
|
112
|
+
max_delay: @options[:wait_for_less_busy_worker] || 0 # Real default is in Configuration::DEFAULTS, this is for unit testing
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
if @options[:fiber_per_request]
|
|
116
|
+
singleton_class.prepend(FiberPerRequest)
|
|
117
|
+
end
|
|
97
118
|
|
|
98
119
|
# make this a hash, since we prefer `key?` over `include?`
|
|
99
120
|
@supported_http_methods =
|
|
@@ -110,7 +131,7 @@ module Puma
|
|
|
110
131
|
temp = !!(@options[:environment] =~ /\A(development|test)\z/)
|
|
111
132
|
@leak_stack_on_error = @options[:environment] ? temp : true
|
|
112
133
|
|
|
113
|
-
@binder = Binder.new(log_writer)
|
|
134
|
+
@binder = Binder.new(log_writer, @options)
|
|
114
135
|
|
|
115
136
|
ENV['RACK_ENV'] ||= "development"
|
|
116
137
|
|
|
@@ -130,7 +151,7 @@ module Puma
|
|
|
130
151
|
class << self
|
|
131
152
|
# @!attribute [r] current
|
|
132
153
|
def current
|
|
133
|
-
Thread.current
|
|
154
|
+
Thread.current.puma_server
|
|
134
155
|
end
|
|
135
156
|
|
|
136
157
|
# :nodoc:
|
|
@@ -161,7 +182,6 @@ module Puma
|
|
|
161
182
|
begin
|
|
162
183
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 1) if skt.kind_of? TCPSocket
|
|
163
184
|
rescue IOError, SystemCallError
|
|
164
|
-
Puma::Util.purge_interrupt_queue
|
|
165
185
|
end
|
|
166
186
|
end
|
|
167
187
|
|
|
@@ -170,7 +190,6 @@ module Puma
|
|
|
170
190
|
begin
|
|
171
191
|
skt.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_CORK, 0) if skt.kind_of? TCPSocket
|
|
172
192
|
rescue IOError, SystemCallError
|
|
173
|
-
Puma::Util.purge_interrupt_queue
|
|
174
193
|
end
|
|
175
194
|
end
|
|
176
195
|
else
|
|
@@ -191,7 +210,6 @@ module Puma
|
|
|
191
210
|
begin
|
|
192
211
|
tcp_info = skt.getsockopt(Socket::IPPROTO_TCP, Socket::TCP_INFO)
|
|
193
212
|
rescue IOError, SystemCallError
|
|
194
|
-
Puma::Util.purge_interrupt_queue
|
|
195
213
|
@precheck_closing = false
|
|
196
214
|
false
|
|
197
215
|
else
|
|
@@ -216,7 +234,6 @@ module Puma
|
|
|
216
234
|
@thread_pool&.spawned
|
|
217
235
|
end
|
|
218
236
|
|
|
219
|
-
|
|
220
237
|
# This number represents the number of requests that
|
|
221
238
|
# the server is capable of taking right now.
|
|
222
239
|
#
|
|
@@ -242,16 +259,19 @@ module Puma
|
|
|
242
259
|
|
|
243
260
|
@status = :run
|
|
244
261
|
|
|
245
|
-
@thread_pool = ThreadPool.new(thread_name,
|
|
262
|
+
@thread_pool = ThreadPool.new(thread_name, options, server: self) { |client| process_client client }
|
|
246
263
|
|
|
247
264
|
if @queue_requests
|
|
248
|
-
@reactor = Reactor.new(@io_selector_backend) { |c|
|
|
265
|
+
@reactor = Reactor.new(@io_selector_backend) { |c|
|
|
266
|
+
# Inversion of control, the reactor is calling a method on the server when it
|
|
267
|
+
# is done buffering a request or receives a new request from a keepalive connection.
|
|
268
|
+
self.reactor_wakeup(c)
|
|
269
|
+
}
|
|
249
270
|
@reactor.run
|
|
250
271
|
end
|
|
251
272
|
|
|
252
|
-
|
|
253
|
-
@thread_pool.
|
|
254
|
-
@thread_pool.auto_trim! if @options[:auto_trim_time]
|
|
273
|
+
@thread_pool.auto_reap! if options[:reaping_time]
|
|
274
|
+
@thread_pool.auto_trim! if @min_threads != @max_threads && options[:auto_trim_time]
|
|
255
275
|
|
|
256
276
|
@check, @notify = Puma::Util.pipe unless @notify
|
|
257
277
|
|
|
@@ -271,12 +291,15 @@ module Puma
|
|
|
271
291
|
# This method is called from the Reactor thread when a queued Client receives data,
|
|
272
292
|
# times out, or when the Reactor is shutting down.
|
|
273
293
|
#
|
|
294
|
+
# While the code lives in the Server, the logic is executed on the reactor thread, independently
|
|
295
|
+
# from the server.
|
|
296
|
+
#
|
|
274
297
|
# It is responsible for ensuring that a request has been completely received
|
|
275
298
|
# before it starts to be processed by the ThreadPool. This may be known as read buffering.
|
|
276
299
|
# If read buffering is not done, and no other read buffering is performed (such as by an application server
|
|
277
300
|
# such as nginx) then the application would be subject to a slow client attack.
|
|
278
301
|
#
|
|
279
|
-
# For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/
|
|
302
|
+
# For a graphical representation of how the request buffer works see [architecture.md](https://github.com/puma/puma/blob/main/docs/architecture.md).
|
|
280
303
|
#
|
|
281
304
|
# The method checks to see if it has the full header and body with
|
|
282
305
|
# the `Puma::Client#try_to_finish` method. If the full request has been sent,
|
|
@@ -305,25 +328,28 @@ module Puma
|
|
|
305
328
|
end
|
|
306
329
|
rescue StandardError => e
|
|
307
330
|
client_error(e, client)
|
|
308
|
-
client
|
|
331
|
+
close_client_safely(client)
|
|
309
332
|
true
|
|
310
333
|
end
|
|
311
334
|
|
|
312
335
|
def handle_servers
|
|
336
|
+
@env_set_http_version = Object.const_defined?(:Rack) && ::Rack.respond_to?(:release) &&
|
|
337
|
+
Gem::Version.new(::Rack.release) < Gem::Version.new('3.1.0')
|
|
338
|
+
|
|
313
339
|
begin
|
|
314
340
|
check = @check
|
|
315
341
|
sockets = [check] + @binder.ios
|
|
316
342
|
pool = @thread_pool
|
|
317
343
|
queue_requests = @queue_requests
|
|
318
|
-
drain =
|
|
344
|
+
drain = options[:drain_on_shutdown] ? 0 : nil
|
|
319
345
|
|
|
320
|
-
addr_send_name, addr_value = case
|
|
346
|
+
addr_send_name, addr_value = case options[:remote_address]
|
|
321
347
|
when :value
|
|
322
|
-
[:peerip=,
|
|
348
|
+
[:peerip=, options[:remote_address_value]]
|
|
323
349
|
when :header
|
|
324
|
-
[:remote_addr_header=,
|
|
350
|
+
[:remote_addr_header=, options[:remote_address_header]]
|
|
325
351
|
when :proxy_protocol
|
|
326
|
-
[:expect_proxy_proto=,
|
|
352
|
+
[:expect_proxy_proto=, options[:remote_address_proxy_protocol]]
|
|
327
353
|
else
|
|
328
354
|
[nil, nil]
|
|
329
355
|
end
|
|
@@ -336,7 +362,7 @@ module Puma
|
|
|
336
362
|
@idle_timeout_reached = true
|
|
337
363
|
|
|
338
364
|
if @clustered
|
|
339
|
-
@worker_write << "
|
|
365
|
+
@worker_write << "#{PipeRequest::PIPE_IDLE}#{Process.pid}\n" rescue nil
|
|
340
366
|
next
|
|
341
367
|
else
|
|
342
368
|
@log_writer.log "- Idle timeout reached"
|
|
@@ -349,15 +375,25 @@ module Puma
|
|
|
349
375
|
|
|
350
376
|
if @idle_timeout_reached && @clustered
|
|
351
377
|
@idle_timeout_reached = false
|
|
352
|
-
@worker_write << "
|
|
378
|
+
@worker_write << "#{PipeRequest::PIPE_IDLE}#{Process.pid}\n" rescue nil
|
|
353
379
|
end
|
|
354
380
|
|
|
355
381
|
ios.first.each do |sock|
|
|
356
382
|
if sock == check
|
|
357
383
|
break if handle_check
|
|
358
384
|
else
|
|
359
|
-
|
|
360
|
-
|
|
385
|
+
# if ThreadPool out_of_band code is running, we don't want to add
|
|
386
|
+
# clients until the code is finished.
|
|
387
|
+
pool.wait_while_out_of_band_running
|
|
388
|
+
|
|
389
|
+
# A well rested herd (cluster) runs faster
|
|
390
|
+
if @cluster_accept_loop_delay.on? && (busy_threads_plus_todo = pool.busy_threads) > 0
|
|
391
|
+
delay = @cluster_accept_loop_delay.calculate(
|
|
392
|
+
max_threads: @max_threads,
|
|
393
|
+
busy_threads_plus_todo: busy_threads_plus_todo
|
|
394
|
+
)
|
|
395
|
+
sleep(delay)
|
|
396
|
+
end
|
|
361
397
|
|
|
362
398
|
io = begin
|
|
363
399
|
sock.accept_nonblock
|
|
@@ -365,11 +401,9 @@ module Puma
|
|
|
365
401
|
next
|
|
366
402
|
end
|
|
367
403
|
drain += 1 if shutting_down?
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
c.send(addr_send_name, addr_value) if addr_value
|
|
372
|
-
}
|
|
404
|
+
client = new_client(io, sock)
|
|
405
|
+
client.send(addr_send_name, addr_value) if addr_value
|
|
406
|
+
pool << client
|
|
373
407
|
end
|
|
374
408
|
end
|
|
375
409
|
rescue IOError, Errno::EBADF
|
|
@@ -406,6 +440,14 @@ module Puma
|
|
|
406
440
|
@events.fire :state, :done
|
|
407
441
|
end
|
|
408
442
|
|
|
443
|
+
# :nodoc:
|
|
444
|
+
def new_client(io, sock)
|
|
445
|
+
client = Client.new(io, @binder.env(sock))
|
|
446
|
+
client.listener = sock
|
|
447
|
+
client.http_content_length_limit = @http_content_length_limit
|
|
448
|
+
client
|
|
449
|
+
end
|
|
450
|
+
|
|
409
451
|
# :nodoc:
|
|
410
452
|
def handle_check
|
|
411
453
|
cmd = @check.read(1)
|
|
@@ -436,17 +478,12 @@ module Puma
|
|
|
436
478
|
#
|
|
437
479
|
# Return true if one or more requests were processed.
|
|
438
480
|
def process_client(client)
|
|
439
|
-
# Advertise this server into the thread
|
|
440
|
-
Thread.current[THREAD_LOCAL_KEY] = self
|
|
441
|
-
|
|
442
|
-
clean_thread_locals = @options[:clean_thread_locals]
|
|
443
481
|
close_socket = true
|
|
444
482
|
|
|
445
483
|
requests = 0
|
|
446
484
|
|
|
447
485
|
begin
|
|
448
|
-
if @queue_requests &&
|
|
449
|
-
!client.eagerly_finish
|
|
486
|
+
if @queue_requests && !client.eagerly_finish
|
|
450
487
|
|
|
451
488
|
client.set_timeout(@first_data_timeout)
|
|
452
489
|
if @reactor.add client
|
|
@@ -459,38 +496,40 @@ module Puma
|
|
|
459
496
|
client.finish(@first_data_timeout)
|
|
460
497
|
end
|
|
461
498
|
|
|
462
|
-
|
|
499
|
+
can_loop = true
|
|
500
|
+
while can_loop
|
|
501
|
+
can_loop = false
|
|
463
502
|
@requests_count += 1
|
|
464
503
|
case handle_request(client, requests + 1)
|
|
465
|
-
when
|
|
466
|
-
break
|
|
504
|
+
when :close
|
|
467
505
|
when :async
|
|
468
506
|
close_socket = false
|
|
469
|
-
|
|
470
|
-
when true
|
|
471
|
-
ThreadPool.clean_thread_locals if clean_thread_locals
|
|
472
|
-
|
|
507
|
+
when :keep_alive
|
|
473
508
|
requests += 1
|
|
474
509
|
|
|
475
|
-
|
|
476
|
-
# socket for a short time before returning to the reactor.
|
|
477
|
-
fast_check = @status == :run
|
|
510
|
+
client.reset
|
|
478
511
|
|
|
479
|
-
#
|
|
480
|
-
#
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
client.reset(fast_check)
|
|
512
|
+
# This indicates data exists in the client read buffer and there may be
|
|
513
|
+
# additional requests on it, so process them
|
|
514
|
+
next_request_ready = if client.has_back_to_back_requests?
|
|
515
|
+
with_force_shutdown(client) { client.process_back_to_back_requests }
|
|
516
|
+
else
|
|
517
|
+
with_force_shutdown(client) { client.eagerly_finish }
|
|
486
518
|
end
|
|
487
519
|
|
|
488
|
-
|
|
489
|
-
|
|
520
|
+
if next_request_ready
|
|
521
|
+
# When Puma has spare threads, allow this one to be monopolized
|
|
522
|
+
# Perf optimization for https://github.com/puma/puma/issues/3788
|
|
523
|
+
if @thread_pool.waiting > 0
|
|
524
|
+
can_loop = true
|
|
525
|
+
else
|
|
526
|
+
@thread_pool << client
|
|
527
|
+
close_socket = false
|
|
528
|
+
end
|
|
529
|
+
elsif @queue_requests
|
|
490
530
|
client.set_timeout @persistent_timeout
|
|
491
531
|
if @reactor.add client
|
|
492
532
|
close_socket = false
|
|
493
|
-
break
|
|
494
533
|
end
|
|
495
534
|
end
|
|
496
535
|
end
|
|
@@ -503,17 +542,21 @@ module Puma
|
|
|
503
542
|
ensure
|
|
504
543
|
client.io_buffer.reset
|
|
505
544
|
|
|
506
|
-
|
|
507
|
-
client.close if close_socket
|
|
508
|
-
rescue IOError, SystemCallError
|
|
509
|
-
Puma::Util.purge_interrupt_queue
|
|
510
|
-
# Already closed
|
|
511
|
-
rescue StandardError => e
|
|
512
|
-
@log_writer.unknown_error e, nil, "Client"
|
|
513
|
-
end
|
|
545
|
+
close_client_safely(client) if close_socket
|
|
514
546
|
end
|
|
515
547
|
end
|
|
516
548
|
|
|
549
|
+
# :nodoc:
|
|
550
|
+
def close_client_safely(client)
|
|
551
|
+
client.close
|
|
552
|
+
rescue IOError, SystemCallError
|
|
553
|
+
# Already closed
|
|
554
|
+
rescue MiniSSL::SSLError => e
|
|
555
|
+
@log_writer.ssl_error e, client.io
|
|
556
|
+
rescue StandardError => e
|
|
557
|
+
@log_writer.unknown_error e, nil, "Client"
|
|
558
|
+
end
|
|
559
|
+
|
|
517
560
|
# Triggers a client timeout if the thread-pool shuts down
|
|
518
561
|
# during execution of the provided block.
|
|
519
562
|
def with_force_shutdown(client, &block)
|
|
@@ -548,7 +591,7 @@ module Puma
|
|
|
548
591
|
# A fallback rack response if +@app+ raises as exception.
|
|
549
592
|
#
|
|
550
593
|
def lowlevel_error(e, env, status=500)
|
|
551
|
-
if handler =
|
|
594
|
+
if handler = options[:lowlevel_error_handler]
|
|
552
595
|
if handler.arity == 1
|
|
553
596
|
return handler.call(e)
|
|
554
597
|
elsif handler.arity == 2
|
|
@@ -569,14 +612,13 @@ module Puma
|
|
|
569
612
|
def response_to_error(client, requests, err, status_code)
|
|
570
613
|
status, headers, res_body = lowlevel_error(err, client.env, status_code)
|
|
571
614
|
prepare_response(status, headers, res_body, requests, client)
|
|
572
|
-
client.write_error(status_code)
|
|
573
615
|
end
|
|
574
616
|
private :response_to_error
|
|
575
617
|
|
|
576
618
|
# Wait for all outstanding requests to finish.
|
|
577
619
|
#
|
|
578
620
|
def graceful_shutdown
|
|
579
|
-
if
|
|
621
|
+
if options[:shutdown_debug]
|
|
580
622
|
threads = Thread.list
|
|
581
623
|
total = threads.size
|
|
582
624
|
|
|
@@ -596,7 +638,7 @@ module Puma
|
|
|
596
638
|
end
|
|
597
639
|
|
|
598
640
|
if @thread_pool
|
|
599
|
-
if timeout =
|
|
641
|
+
if timeout = options[:force_shutdown_after]
|
|
600
642
|
@thread_pool.shutdown timeout.to_f
|
|
601
643
|
else
|
|
602
644
|
@thread_pool.shutdown
|
|
@@ -608,11 +650,10 @@ module Puma
|
|
|
608
650
|
@notify << message
|
|
609
651
|
rescue IOError, NoMethodError, Errno::EPIPE, Errno::EBADF
|
|
610
652
|
# The server, in another thread, is shutting down
|
|
611
|
-
Puma::Util.purge_interrupt_queue
|
|
612
653
|
rescue RuntimeError => e
|
|
613
654
|
# Temporary workaround for https://bugs.ruby-lang.org/issues/13239
|
|
614
655
|
if e.message.include?('IOError')
|
|
615
|
-
|
|
656
|
+
# ignore
|
|
616
657
|
else
|
|
617
658
|
raise e
|
|
618
659
|
end
|
|
@@ -643,13 +684,33 @@ module Puma
|
|
|
643
684
|
|
|
644
685
|
# List of methods invoked by #stats.
|
|
645
686
|
# @version 5.0.0
|
|
646
|
-
STAT_METHODS = [
|
|
687
|
+
STAT_METHODS = [
|
|
688
|
+
:backlog,
|
|
689
|
+
:running,
|
|
690
|
+
:pool_capacity,
|
|
691
|
+
:busy_threads,
|
|
692
|
+
:backlog_max,
|
|
693
|
+
:max_threads,
|
|
694
|
+
:requests_count,
|
|
695
|
+
:reactor_max,
|
|
696
|
+
].freeze
|
|
647
697
|
|
|
648
698
|
# Returns a hash of stats about the running server for reporting purposes.
|
|
649
699
|
# @version 5.0.0
|
|
650
700
|
# @!attribute [r] stats
|
|
701
|
+
# @return [Hash] hash containing stat info from `Server` and `ThreadPool`
|
|
651
702
|
def stats
|
|
652
|
-
|
|
703
|
+
stats = @thread_pool&.stats || {}
|
|
704
|
+
stats[:max_threads] = @max_threads
|
|
705
|
+
stats[:requests_count] = @requests_count
|
|
706
|
+
stats[:reactor_max] = @reactor.reactor_max if @reactor
|
|
707
|
+
reset_max
|
|
708
|
+
stats
|
|
709
|
+
end
|
|
710
|
+
|
|
711
|
+
def reset_max
|
|
712
|
+
@reactor.reactor_max = 0 if @reactor
|
|
713
|
+
@thread_pool&.reset_max
|
|
653
714
|
end
|
|
654
715
|
|
|
655
716
|
# below are 'delegations' to binder
|
data/lib/puma/single.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Puma
|
|
|
17
17
|
def stats
|
|
18
18
|
{
|
|
19
19
|
started_at: utc_iso8601(@started_at)
|
|
20
|
-
}.merge(@server
|
|
20
|
+
}.merge(@server&.stats || {}).merge(super)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def restart
|
|
@@ -49,13 +49,16 @@ module Puma
|
|
|
49
49
|
|
|
50
50
|
start_control
|
|
51
51
|
|
|
52
|
-
@server =
|
|
53
|
-
server_thread = server.run
|
|
52
|
+
@server = start_server
|
|
53
|
+
server_thread = @server.run
|
|
54
54
|
|
|
55
55
|
log "Use Ctrl-C to stop"
|
|
56
|
+
|
|
57
|
+
warn_ruby_mn_threads
|
|
58
|
+
|
|
56
59
|
redirect_io
|
|
57
60
|
|
|
58
|
-
@events.
|
|
61
|
+
@events.fire_after_booted!
|
|
59
62
|
|
|
60
63
|
debug_loaded_extensions("Loaded Extensions:") if @log_writer.debug?
|
|
61
64
|
|
data/lib/puma/state_file.rb
CHANGED
|
@@ -32,10 +32,11 @@ module Puma
|
|
|
32
32
|
"#{k}: \"#{v}\"\n" : "#{k}: #{v}\n")
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
|
+
|
|
35
36
|
if permission
|
|
36
|
-
File.write path, contents, mode: 'wb:UTF-8'
|
|
37
|
-
else
|
|
38
37
|
File.write path, contents, mode: 'wb:UTF-8', perm: permission
|
|
38
|
+
else
|
|
39
|
+
File.write path, contents, mode: 'wb:UTF-8'
|
|
39
40
|
end
|
|
40
41
|
end
|
|
41
42
|
|