puma 5.0.3 → 5.2.1
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 +110 -40
- data/README.md +48 -18
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +1 -1
- data/docs/fork_worker.md +2 -0
- data/docs/kubernetes.md +66 -0
- data/docs/plugins.md +1 -1
- data/docs/rails_dev_mode.md +29 -0
- data/docs/stats.md +142 -0
- data/docs/systemd.md +24 -2
- data/ext/puma_http11/extconf.rb +18 -5
- data/ext/puma_http11/http11_parser.c +45 -47
- data/ext/puma_http11/http11_parser.java.rl +1 -1
- data/ext/puma_http11/http11_parser.rl +1 -1
- data/ext/puma_http11/mini_ssl.c +162 -84
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +5 -7
- data/ext/puma_http11/puma_http11.c +8 -2
- data/lib/puma.rb +20 -10
- data/lib/puma/app/status.rb +4 -7
- data/lib/puma/binder.rb +60 -24
- data/lib/puma/cli.rb +4 -0
- data/lib/puma/client.rb +4 -9
- data/lib/puma/cluster.rb +13 -7
- data/lib/puma/cluster/worker.rb +8 -2
- data/lib/puma/cluster/worker_handle.rb +5 -2
- data/lib/puma/configuration.rb +13 -1
- data/lib/puma/const.rb +11 -3
- data/lib/puma/control_cli.rb +73 -70
- data/lib/puma/detect.rb +14 -10
- data/lib/puma/dsl.rb +100 -22
- data/lib/puma/error_logger.rb +10 -3
- data/lib/puma/events.rb +18 -3
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +52 -6
- data/lib/puma/minissl.rb +48 -17
- data/lib/puma/minissl/context_builder.rb +6 -0
- data/lib/puma/null_io.rb +4 -0
- data/lib/puma/reactor.rb +19 -12
- data/lib/puma/request.rb +20 -7
- data/lib/puma/runner.rb +14 -7
- data/lib/puma/server.rb +20 -75
- data/lib/puma/state_file.rb +5 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/rack/handler/puma.rb +1 -0
- metadata +12 -6
data/lib/puma/detect.rb
CHANGED
@@ -1,32 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This file can be loaded independently of puma.rb, so it cannot have any code
|
4
|
+
# that assumes puma.rb is loaded.
|
5
|
+
|
6
|
+
|
3
7
|
module Puma
|
4
|
-
#
|
5
|
-
|
8
|
+
# @version 5.2.1
|
9
|
+
HAS_FORK = ::Process.respond_to? :fork
|
6
10
|
|
7
|
-
|
8
|
-
HAS_SSL
|
9
|
-
end
|
11
|
+
IS_JRUBY = Object.const_defined? :JRUBY_VERSION
|
10
12
|
|
11
|
-
|
13
|
+
IS_WINDOWS = !!(RUBY_PLATFORM =~ /mswin|ming|cygwin/ ||
|
14
|
+
IS_JRUBY && RUBY_DESCRIPTION =~ /mswin/)
|
15
|
+
|
16
|
+
# @version 5.2.0
|
17
|
+
IS_MRI = (RUBY_ENGINE == 'ruby' || RUBY_ENGINE.nil?)
|
12
18
|
|
13
19
|
def self.jruby?
|
14
20
|
IS_JRUBY
|
15
21
|
end
|
16
22
|
|
17
|
-
IS_WINDOWS = RUBY_PLATFORM =~ /mswin|ming|cygwin/
|
18
|
-
|
19
23
|
def self.windows?
|
20
24
|
IS_WINDOWS
|
21
25
|
end
|
22
26
|
|
23
27
|
# @version 5.0.0
|
24
28
|
def self.mri?
|
25
|
-
|
29
|
+
IS_MRI
|
26
30
|
end
|
27
31
|
|
28
32
|
# @version 5.0.0
|
29
33
|
def self.forkable?
|
30
|
-
|
34
|
+
HAS_FORK
|
31
35
|
end
|
32
36
|
end
|
data/lib/puma/dsl.rb
CHANGED
@@ -34,6 +34,40 @@ module Puma
|
|
34
34
|
class DSL
|
35
35
|
include ConfigDefault
|
36
36
|
|
37
|
+
# convenience method so logic can be used in CI
|
38
|
+
# @see ssl_bind
|
39
|
+
#
|
40
|
+
def self.ssl_bind_str(host, port, opts)
|
41
|
+
verify = opts.fetch(:verify_mode, 'none').to_s
|
42
|
+
|
43
|
+
tls_str =
|
44
|
+
if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
|
45
|
+
elsif opts[:no_tlsv1] then '&no_tlsv1=true'
|
46
|
+
else ''
|
47
|
+
end
|
48
|
+
|
49
|
+
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
50
|
+
|
51
|
+
if defined?(JRUBY_VERSION)
|
52
|
+
ssl_cipher_list = opts[:ssl_cipher_list] ?
|
53
|
+
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
|
54
|
+
|
55
|
+
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
56
|
+
|
57
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
|
58
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
59
|
+
else
|
60
|
+
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
61
|
+
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
62
|
+
|
63
|
+
v_flags = (ary = opts[:verification_flags]) ?
|
64
|
+
"&verification_flags=#{Array(ary).join ','}" : nil
|
65
|
+
|
66
|
+
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
|
67
|
+
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}#{v_flags}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
37
71
|
def initialize(options, config)
|
38
72
|
@config = config
|
39
73
|
@options = options
|
@@ -191,13 +225,39 @@ module Puma
|
|
191
225
|
@options[:binds] = []
|
192
226
|
end
|
193
227
|
|
228
|
+
# Bind to (systemd) activated sockets, regardless of configured binds.
|
229
|
+
#
|
230
|
+
# Systemd can present sockets as file descriptors that are already opened.
|
231
|
+
# By default Puma will use these but only if it was explicitly told to bind
|
232
|
+
# to the socket. If not, it will close the activated sockets. This means
|
233
|
+
# all configuration is duplicated.
|
234
|
+
#
|
235
|
+
# Binds can contain additional configuration, but only SSL config is really
|
236
|
+
# relevant since the unix and TCP socket options are ignored.
|
237
|
+
#
|
238
|
+
# This means there is a lot of duplicated configuration for no additional
|
239
|
+
# value in most setups. This method tells the launcher to bind to all
|
240
|
+
# activated sockets, regardless of existing bind.
|
241
|
+
#
|
242
|
+
# To clear configured binds, the value only can be passed. This will clear
|
243
|
+
# out any binds that may have been configured.
|
244
|
+
#
|
245
|
+
# @example Use any systemd activated sockets as well as configured binds
|
246
|
+
# bind_to_activated_sockets
|
247
|
+
#
|
248
|
+
# @example Only bind to systemd activated sockets, ignoring other binds
|
249
|
+
# bind_to_activated_sockets 'only'
|
250
|
+
def bind_to_activated_sockets(bind=true)
|
251
|
+
@options[:bind_to_activated_sockets] = bind
|
252
|
+
end
|
253
|
+
|
194
254
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
195
255
|
#
|
196
256
|
# @example
|
197
257
|
# port 9292
|
198
258
|
def port(port, host=nil)
|
199
259
|
host ||= default_host
|
200
|
-
bind
|
260
|
+
bind URI::Generic.build(scheme: 'tcp', host: host, port: Integer(port)).to_s
|
201
261
|
end
|
202
262
|
|
203
263
|
# Define how long persistent connections can be idle before Puma closes them.
|
@@ -345,7 +405,10 @@ module Puma
|
|
345
405
|
# Configure +min+ to be the minimum number of threads to use to answer
|
346
406
|
# requests and +max+ the maximum.
|
347
407
|
#
|
348
|
-
# The default is
|
408
|
+
# The default is the environment variables +PUMA_MIN_THREADS+ / +PUMA_MAX_THREADS+
|
409
|
+
# (or +MIN_THREADS+ / +MAX_THREADS+ if the +PUMA_+ variables aren't set).
|
410
|
+
#
|
411
|
+
# If these environment variables aren't set, the default is "0, 5" in MRI or "0, 16" for other interpreters.
|
349
412
|
#
|
350
413
|
# @example
|
351
414
|
# threads 0, 16
|
@@ -375,29 +438,17 @@ module Puma
|
|
375
438
|
# key: path_to_key,
|
376
439
|
# ssl_cipher_filter: cipher_filter, # optional
|
377
440
|
# verify_mode: verify_mode, # default 'none'
|
441
|
+
# verification_flags: flags, # optional, not supported by JRuby
|
378
442
|
# }
|
379
|
-
# @example For JRuby
|
443
|
+
# @example For JRuby, two keys are required: keystore & keystore_pass.
|
380
444
|
# ssl_bind '127.0.0.1', '9292', {
|
381
|
-
# cert: path_to_cert,
|
382
|
-
# key: path_to_key,
|
383
|
-
# ssl_cipher_filter: cipher_filter, # optional
|
384
|
-
# verify_mode: verify_mode, # default 'none'
|
385
445
|
# keystore: path_to_keystore,
|
386
|
-
# keystore_pass: password
|
446
|
+
# keystore_pass: password,
|
447
|
+
# ssl_cipher_list: cipher_list, # optional
|
448
|
+
# verify_mode: verify_mode # default 'none'
|
387
449
|
# }
|
388
450
|
def ssl_bind(host, port, opts)
|
389
|
-
|
390
|
-
no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
|
391
|
-
no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
|
392
|
-
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
393
|
-
|
394
|
-
if defined?(JRUBY_VERSION)
|
395
|
-
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
396
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
397
|
-
else
|
398
|
-
ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
|
399
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
400
|
-
end
|
451
|
+
bind self.class.ssl_bind_str(host, port, opts)
|
401
452
|
end
|
402
453
|
|
403
454
|
# Use +path+ as the file to store the server info state. This is
|
@@ -422,7 +473,8 @@ module Puma
|
|
422
473
|
# How many worker processes to run. Typically this is set to
|
423
474
|
# the number of available cores.
|
424
475
|
#
|
425
|
-
# The default is
|
476
|
+
# The default is the value of the environment variable +WEB_CONCURRENCY+ if
|
477
|
+
# set, otherwise 0.
|
426
478
|
#
|
427
479
|
# @note Cluster mode only.
|
428
480
|
# @see Puma::Cluster
|
@@ -561,7 +613,7 @@ module Puma
|
|
561
613
|
end
|
562
614
|
|
563
615
|
# Preload the application before starting the workers; this conflicts with
|
564
|
-
# phased restart feature.
|
616
|
+
# phased restart feature. On by default if your app uses more than 1 worker.
|
565
617
|
#
|
566
618
|
# @note Cluster mode only.
|
567
619
|
# @example
|
@@ -810,5 +862,31 @@ module Puma
|
|
810
862
|
def nakayoshi_fork(enabled=true)
|
811
863
|
@options[:nakayoshi_fork] = enabled
|
812
864
|
end
|
865
|
+
|
866
|
+
# The number of requests to attempt inline before sending a client back to
|
867
|
+
# the reactor to be subject to normal ordering.
|
868
|
+
#
|
869
|
+
def max_fast_inline(num_of_requests)
|
870
|
+
@options[:max_fast_inline] = Float(num_of_requests)
|
871
|
+
end
|
872
|
+
|
873
|
+
# Specify the backend for the IO selector.
|
874
|
+
#
|
875
|
+
# Provided values will be passed directly to +NIO::Selector.new+, with the
|
876
|
+
# exception of +:auto+ which will let nio4r choose the backend.
|
877
|
+
#
|
878
|
+
# Check the documentation of +NIO::Selector.backends+ for the list of valid
|
879
|
+
# options. Note that the available options on your system will depend on the
|
880
|
+
# operating system. If you want to use the pure Ruby backend (not
|
881
|
+
# recommended due to its comparatively low performance), set environment
|
882
|
+
# variable +NIO4R_PURE+ to +true+.
|
883
|
+
#
|
884
|
+
# The default is +:auto+.
|
885
|
+
#
|
886
|
+
# @see https://github.com/socketry/nio4r/blob/master/lib/nio/selector.rb
|
887
|
+
#
|
888
|
+
def io_selector_backend(backend)
|
889
|
+
@options[:io_selector_backend] = backend.to_sym
|
890
|
+
end
|
813
891
|
end
|
814
892
|
end
|
data/lib/puma/error_logger.rb
CHANGED
@@ -15,7 +15,6 @@ module Puma
|
|
15
15
|
|
16
16
|
def initialize(ioerr)
|
17
17
|
@ioerr = ioerr
|
18
|
-
@ioerr.sync = true
|
19
18
|
|
20
19
|
@debug = ENV.key? 'PUMA_DEBUG'
|
21
20
|
end
|
@@ -32,7 +31,7 @@ module Puma
|
|
32
31
|
# and before all remaining info.
|
33
32
|
#
|
34
33
|
def info(options={})
|
35
|
-
|
34
|
+
log title(options)
|
36
35
|
end
|
37
36
|
|
38
37
|
# Print occured error details only if
|
@@ -54,7 +53,7 @@ module Puma
|
|
54
53
|
string_block << request_dump(req) if request_parsed?(req)
|
55
54
|
string_block << error.backtrace if error
|
56
55
|
|
57
|
-
|
56
|
+
log string_block.join("\n")
|
58
57
|
end
|
59
58
|
|
60
59
|
def title(options={})
|
@@ -93,5 +92,13 @@ module Puma
|
|
93
92
|
def request_parsed?(req)
|
94
93
|
req && req.env[REQUEST_METHOD]
|
95
94
|
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def log(str)
|
99
|
+
ioerr.puts str
|
100
|
+
|
101
|
+
ioerr.flush unless ioerr.sync
|
102
|
+
end
|
96
103
|
end
|
97
104
|
end
|
data/lib/puma/events.rb
CHANGED
@@ -30,9 +30,6 @@ module Puma
|
|
30
30
|
@stdout = stdout
|
31
31
|
@stderr = stderr
|
32
32
|
|
33
|
-
@stdout.sync = true
|
34
|
-
@stderr.sync = true
|
35
|
-
|
36
33
|
@debug = ENV.key? 'PUMA_DEBUG'
|
37
34
|
@error_logger = ErrorLogger.new(@stderr)
|
38
35
|
|
@@ -66,6 +63,8 @@ module Puma
|
|
66
63
|
#
|
67
64
|
def log(str)
|
68
65
|
@stdout.puts format(str) if @stdout.respond_to? :puts
|
66
|
+
|
67
|
+
@stdout.flush unless @stdout.sync
|
69
68
|
rescue Errno::EPIPE
|
70
69
|
end
|
71
70
|
|
@@ -137,10 +136,26 @@ module Puma
|
|
137
136
|
register(:on_booted, &block)
|
138
137
|
end
|
139
138
|
|
139
|
+
def on_restart(&block)
|
140
|
+
register(:on_restart, &block)
|
141
|
+
end
|
142
|
+
|
143
|
+
def on_stopped(&block)
|
144
|
+
register(:on_stopped, &block)
|
145
|
+
end
|
146
|
+
|
140
147
|
def fire_on_booted!
|
141
148
|
fire(:on_booted)
|
142
149
|
end
|
143
150
|
|
151
|
+
def fire_on_restart!
|
152
|
+
fire(:on_restart)
|
153
|
+
end
|
154
|
+
|
155
|
+
def fire_on_stopped!
|
156
|
+
fire(:on_stopped)
|
157
|
+
end
|
158
|
+
|
144
159
|
DEFAULT = new(STDOUT, STDERR)
|
145
160
|
|
146
161
|
# Returns an Events object which writes its status to 2 StringIO
|
data/lib/puma/json.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Puma
|
5
|
+
|
6
|
+
# Puma deliberately avoids the use of the json gem and instead performs JSON
|
7
|
+
# serialization without any external dependencies. In a puma cluster, loading
|
8
|
+
# any gem into the puma master process means that operators cannot use a
|
9
|
+
# phased restart to upgrade their application if the new version of that
|
10
|
+
# application uses a different version of that gem. The json gem in
|
11
|
+
# particular is additionally problematic because it leverages native
|
12
|
+
# extensions. If the puma master process relies on a gem with native
|
13
|
+
# extensions and operators remove gems from disk related to old releases,
|
14
|
+
# subsequent phased restarts can fail.
|
15
|
+
#
|
16
|
+
# The implementation of JSON serialization in this module is not designed to
|
17
|
+
# be particularly full-featured or fast. It just has to handle the few places
|
18
|
+
# where Puma relies on JSON serialization internally.
|
19
|
+
|
20
|
+
module JSON
|
21
|
+
QUOTE = /"/
|
22
|
+
BACKSLASH = /\\/
|
23
|
+
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
24
|
+
CHAR_TO_ESCAPE = Regexp.union QUOTE, BACKSLASH, CONTROL_CHAR_TO_ESCAPE
|
25
|
+
|
26
|
+
class SerializationError < StandardError; end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def generate(value)
|
30
|
+
StringIO.open do |io|
|
31
|
+
serialize_value io, value
|
32
|
+
io.string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def serialize_value(output, value)
|
39
|
+
case value
|
40
|
+
when Hash
|
41
|
+
output << '{'
|
42
|
+
value.each_with_index do |(k, v), index|
|
43
|
+
output << ',' if index != 0
|
44
|
+
serialize_object_key output, k
|
45
|
+
output << ':'
|
46
|
+
serialize_value output, v
|
47
|
+
end
|
48
|
+
output << '}'
|
49
|
+
when Array
|
50
|
+
output << '['
|
51
|
+
value.each_with_index do |member, index|
|
52
|
+
output << ',' if index != 0
|
53
|
+
serialize_value output, member
|
54
|
+
end
|
55
|
+
output << ']'
|
56
|
+
when Integer, Float
|
57
|
+
output << value.to_s
|
58
|
+
when String
|
59
|
+
serialize_string output, value
|
60
|
+
when true
|
61
|
+
output << 'true'
|
62
|
+
when false
|
63
|
+
output << 'false'
|
64
|
+
when nil
|
65
|
+
output << 'null'
|
66
|
+
else
|
67
|
+
raise SerializationError, "Unexpected value of type #{value.class}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def serialize_string(output, value)
|
72
|
+
output << '"'
|
73
|
+
output << value.gsub(CHAR_TO_ESCAPE) do |character|
|
74
|
+
case character
|
75
|
+
when BACKSLASH
|
76
|
+
'\\\\'
|
77
|
+
when QUOTE
|
78
|
+
'\\"'
|
79
|
+
when CONTROL_CHAR_TO_ESCAPE
|
80
|
+
'\u%.4X' % character.ord
|
81
|
+
end
|
82
|
+
end
|
83
|
+
output << '"'
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize_object_key(output, value)
|
87
|
+
case value
|
88
|
+
when Symbol, String
|
89
|
+
serialize_string output, value.to_s
|
90
|
+
else
|
91
|
+
raise SerializationError, "Could not serialize object of type #{value.class} as object key"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/puma/launcher.rb
CHANGED
@@ -58,6 +58,13 @@ module Puma
|
|
58
58
|
|
59
59
|
@config.load
|
60
60
|
|
61
|
+
if @config.options[:bind_to_activated_sockets]
|
62
|
+
@config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
|
63
|
+
@config.options[:binds],
|
64
|
+
@config.options[:bind_to_activated_sockets] == 'only'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
61
68
|
@options = @config.options
|
62
69
|
@config.clamp
|
63
70
|
|
@@ -87,6 +94,8 @@ module Puma
|
|
87
94
|
Puma.stats_object = @runner
|
88
95
|
|
89
96
|
@status = :run
|
97
|
+
|
98
|
+
log_config if ENV['PUMA_LOG_CONFIG']
|
90
99
|
end
|
91
100
|
|
92
101
|
attr_reader :binder, :events, :config, :options, :restart_dir
|
@@ -168,6 +177,7 @@ module Puma
|
|
168
177
|
|
169
178
|
setup_signals
|
170
179
|
set_process_title
|
180
|
+
integrate_with_systemd
|
171
181
|
@runner.run
|
172
182
|
|
173
183
|
case @status
|
@@ -207,6 +217,10 @@ module Puma
|
|
207
217
|
def close_binder_listeners
|
208
218
|
@runner.close_control_listeners
|
209
219
|
@binder.close_listeners
|
220
|
+
unless @status == :restart
|
221
|
+
log "=== puma shutdown: #{Time.now} ==="
|
222
|
+
log "- Goodbye!"
|
223
|
+
end
|
210
224
|
end
|
211
225
|
|
212
226
|
# @!attribute [r] thread_status
|
@@ -229,11 +243,10 @@ module Puma
|
|
229
243
|
def write_pid
|
230
244
|
path = @options[:pidfile]
|
231
245
|
return unless path
|
232
|
-
|
233
|
-
File.
|
234
|
-
cur = Process.pid
|
246
|
+
cur_pid = Process.pid
|
247
|
+
File.write path, cur_pid, mode: 'wb:UTF-8'
|
235
248
|
at_exit do
|
236
|
-
delete_pidfile if
|
249
|
+
delete_pidfile if cur_pid == Process.pid
|
237
250
|
end
|
238
251
|
end
|
239
252
|
|
@@ -242,6 +255,7 @@ module Puma
|
|
242
255
|
end
|
243
256
|
|
244
257
|
def restart!
|
258
|
+
@events.fire_on_restart!
|
245
259
|
@config.run_hooks :on_restart, self, @events
|
246
260
|
|
247
261
|
if Puma.jruby?
|
@@ -316,6 +330,30 @@ module Puma
|
|
316
330
|
end
|
317
331
|
end
|
318
332
|
|
333
|
+
#
|
334
|
+
# Puma's systemd integration allows Puma to inform systemd:
|
335
|
+
# 1. when it has successfully started
|
336
|
+
# 2. when it is starting shutdown
|
337
|
+
# 3. periodically for a liveness check with a watchdog thread
|
338
|
+
#
|
339
|
+
|
340
|
+
def integrate_with_systemd
|
341
|
+
return unless ENV["NOTIFY_SOCKET"]
|
342
|
+
|
343
|
+
begin
|
344
|
+
require 'puma/systemd'
|
345
|
+
rescue LoadError
|
346
|
+
log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
|
347
|
+
return
|
348
|
+
end
|
349
|
+
|
350
|
+
log "* Enabling systemd notification integration"
|
351
|
+
|
352
|
+
systemd = Systemd.new(@events)
|
353
|
+
systemd.hook_events
|
354
|
+
systemd.start_watchdog
|
355
|
+
end
|
356
|
+
|
319
357
|
def spec_for_gem(gem_name)
|
320
358
|
Bundler.rubygems.loaded_specs(gem_name)
|
321
359
|
end
|
@@ -338,9 +376,8 @@ module Puma
|
|
338
376
|
end
|
339
377
|
|
340
378
|
def graceful_stop
|
379
|
+
@events.fire_on_stopped!
|
341
380
|
@runner.stop_blocked
|
342
|
-
log "=== puma shutdown: #{Time.now} ==="
|
343
|
-
log "- Goodbye!"
|
344
381
|
end
|
345
382
|
|
346
383
|
def set_process_title
|
@@ -493,5 +530,14 @@ module Puma
|
|
493
530
|
Bundler.with_unbundled_env { yield }
|
494
531
|
end
|
495
532
|
end
|
533
|
+
|
534
|
+
def log_config
|
535
|
+
log "Configuration:"
|
536
|
+
|
537
|
+
@config.final_options
|
538
|
+
.each { |config_key, value| log "- #{config_key}: #{value}" }
|
539
|
+
|
540
|
+
log "\n"
|
541
|
+
end
|
496
542
|
end
|
497
543
|
end
|