puma 3.7.1 → 4.1.0
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 +5 -5
- data/History.md +229 -1
- data/README.md +179 -212
- data/docs/architecture.md +37 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +24 -4
- 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/plugins.md +28 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +56 -3
- data/docs/systemd.md +130 -37
- data/ext/puma_http11/PumaHttp11Service.java +2 -0
- data/ext/puma_http11/extconf.rb +8 -0
- data/ext/puma_http11/http11_parser.c +84 -84
- data/ext/puma_http11/http11_parser.rl +9 -9
- data/ext/puma_http11/mini_ssl.c +105 -9
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +13 -16
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +72 -0
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
- data/lib/puma.rb +10 -0
- data/lib/puma/accept_nonblock.rb +2 -0
- data/lib/puma/app/status.rb +13 -0
- data/lib/puma/binder.rb +33 -18
- data/lib/puma/cli.rb +48 -33
- data/lib/puma/client.rb +94 -22
- data/lib/puma/cluster.rb +69 -21
- data/lib/puma/commonlogger.rb +2 -0
- data/lib/puma/configuration.rb +134 -136
- data/lib/puma/const.rb +16 -2
- data/lib/puma/control_cli.rb +31 -18
- data/lib/puma/convenient.rb +5 -3
- data/lib/puma/daemon_ext.rb +2 -0
- data/lib/puma/delegation.rb +2 -0
- data/lib/puma/detect.rb +2 -0
- data/lib/puma/dsl.rb +349 -113
- data/lib/puma/events.rb +8 -4
- data/lib/puma/io_buffer.rb +3 -6
- data/lib/puma/jruby_restart.rb +2 -1
- data/lib/puma/launcher.rb +60 -36
- data/lib/puma/minissl.rb +85 -28
- data/lib/puma/null_io.rb +2 -0
- data/lib/puma/plugin.rb +2 -0
- data/lib/puma/plugin/tmp_restart.rb +3 -2
- data/lib/puma/rack/builder.rb +4 -1
- data/lib/puma/rack/urlmap.rb +2 -0
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +218 -30
- data/lib/puma/runner.rb +18 -4
- data/lib/puma/server.rb +149 -56
- data/lib/puma/single.rb +16 -5
- data/lib/puma/state_file.rb +2 -0
- data/lib/puma/tcp_logger.rb +2 -0
- data/lib/puma/thread_pool.rb +59 -6
- data/lib/puma/util.rb +2 -6
- data/lib/rack/handler/puma.rb +58 -19
- data/tools/jungle/README.md +12 -2
- data/tools/jungle/init.d/README.md +2 -0
- data/tools/jungle/init.d/puma +8 -8
- data/tools/jungle/init.d/run-puma +1 -1
- data/tools/jungle/rc.d/README.md +74 -0
- data/tools/jungle/rc.d/puma +61 -0
- data/tools/jungle/rc.d/puma.conf +10 -0
- data/tools/trickletest.rb +1 -1
- metadata +25 -85
- data/.github/issue_template.md +0 -20
- data/Gemfile +0 -12
- data/Manifest.txt +0 -77
- data/Rakefile +0 -158
- data/gemfiles/2.1-Gemfile +0 -12
- data/lib/puma/compat.rb +0 -14
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_193.rb +0 -33
- data/puma.gemspec +0 -52
data/lib/puma/const.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
#encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
module Puma
|
3
5
|
class UnsupportedOption < RuntimeError
|
4
6
|
end
|
@@ -53,6 +55,8 @@ module Puma
|
|
53
55
|
415 => 'Unsupported Media Type',
|
54
56
|
416 => 'Range Not Satisfiable',
|
55
57
|
417 => 'Expectation Failed',
|
58
|
+
418 => 'I\'m A Teapot',
|
59
|
+
421 => 'Misdirected Request',
|
56
60
|
422 => 'Unprocessable Entity',
|
57
61
|
423 => 'Locked',
|
58
62
|
424 => 'Failed Dependency',
|
@@ -60,6 +64,7 @@ module Puma
|
|
60
64
|
428 => 'Precondition Required',
|
61
65
|
429 => 'Too Many Requests',
|
62
66
|
431 => 'Request Header Fields Too Large',
|
67
|
+
451 => 'Unavailable For Legal Reasons',
|
63
68
|
500 => 'Internal Server Error',
|
64
69
|
501 => 'Not Implemented',
|
65
70
|
502 => 'Bad Gateway',
|
@@ -95,8 +100,8 @@ module Puma
|
|
95
100
|
# too taxing on performance.
|
96
101
|
module Const
|
97
102
|
|
98
|
-
PUMA_VERSION = VERSION = "
|
99
|
-
CODE_NAME = "
|
103
|
+
PUMA_VERSION = VERSION = "4.1.0".freeze
|
104
|
+
CODE_NAME = "Fourth and One".freeze
|
100
105
|
PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
|
101
106
|
|
102
107
|
FAST_TRACK_KA_TIMEOUT = 0.2
|
@@ -155,6 +160,9 @@ module Puma
|
|
155
160
|
LINE_END = "\r\n".freeze
|
156
161
|
REMOTE_ADDR = "REMOTE_ADDR".freeze
|
157
162
|
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
|
163
|
+
HTTP_X_FORWARDED_SSL = "HTTP_X_FORWARDED_SSL".freeze
|
164
|
+
HTTP_X_FORWARDED_SCHEME = "HTTP_X_FORWARDED_SCHEME".freeze
|
165
|
+
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO".freeze
|
158
166
|
|
159
167
|
SERVER_NAME = "SERVER_NAME".freeze
|
160
168
|
SERVER_PORT = "SERVER_PORT".freeze
|
@@ -220,5 +228,11 @@ module Puma
|
|
220
228
|
HIJACK_P = "rack.hijack?".freeze
|
221
229
|
HIJACK = "rack.hijack".freeze
|
222
230
|
HIJACK_IO = "rack.hijack_io".freeze
|
231
|
+
|
232
|
+
EARLY_HINTS = "rack.early_hints".freeze
|
233
|
+
|
234
|
+
# Mininum interval to checks worker health
|
235
|
+
WORKER_CHECK_INTERVAL = 5
|
236
|
+
|
223
237
|
end
|
224
238
|
end
|
data/lib/puma/control_cli.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'optparse'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
require_relative 'state_file'
|
5
|
+
require_relative 'const'
|
6
|
+
require_relative 'detect'
|
7
|
+
require_relative 'configuration'
|
6
8
|
require 'uri'
|
7
9
|
require 'socket'
|
8
10
|
|
9
11
|
module Puma
|
10
12
|
class ControlCLI
|
11
13
|
|
12
|
-
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
|
14
|
+
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
|
13
15
|
|
14
16
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
15
17
|
@state = nil
|
@@ -69,6 +71,7 @@ module Puma
|
|
69
71
|
end
|
70
72
|
|
71
73
|
opts.order!(argv) { |a| opts.terminate a }
|
74
|
+
opts.parse!
|
72
75
|
|
73
76
|
@command = argv.shift
|
74
77
|
|
@@ -78,11 +81,12 @@ module Puma
|
|
78
81
|
end
|
79
82
|
|
80
83
|
if @config_file
|
81
|
-
config = Puma::Configuration.
|
82
|
-
|
83
|
-
@
|
84
|
+
config = Puma::Configuration.new({ config_files: [@config_file] }, {})
|
85
|
+
config.load
|
86
|
+
@state ||= config.options[:state]
|
87
|
+
@control_url ||= config.options[:control_url]
|
84
88
|
@control_auth_token ||= config.options[:control_auth_token]
|
85
|
-
@pidfile
|
89
|
+
@pidfile ||= config.options[:pidfile]
|
86
90
|
end
|
87
91
|
end
|
88
92
|
|
@@ -126,7 +130,7 @@ module Puma
|
|
126
130
|
uri = URI.parse @control_url
|
127
131
|
|
128
132
|
# create server object by scheme
|
129
|
-
|
133
|
+
server = case uri.scheme
|
130
134
|
when "tcp"
|
131
135
|
TCPSocket.new uri.host, uri.port
|
132
136
|
when "unix"
|
@@ -144,9 +148,9 @@ module Puma
|
|
144
148
|
url = url + "?token=#{@control_auth_token}"
|
145
149
|
end
|
146
150
|
|
147
|
-
|
151
|
+
server << "GET #{url} HTTP/1.0\r\n\r\n"
|
148
152
|
|
149
|
-
unless data =
|
153
|
+
unless data = server.read
|
150
154
|
raise "Server closed connection before responding"
|
151
155
|
end
|
152
156
|
|
@@ -167,10 +171,10 @@ module Puma
|
|
167
171
|
end
|
168
172
|
|
169
173
|
message "Command #{@command} sent success"
|
170
|
-
message response.last if @command == "stats"
|
174
|
+
message response.last if @command == "stats" || @command == "gc-stats"
|
171
175
|
end
|
172
|
-
|
173
|
-
|
176
|
+
ensure
|
177
|
+
server.close if server && !server.closed?
|
174
178
|
end
|
175
179
|
|
176
180
|
def send_signal
|
@@ -201,8 +205,17 @@ module Puma
|
|
201
205
|
when "phased-restart"
|
202
206
|
Process.kill "SIGUSR1", @pid
|
203
207
|
|
208
|
+
when "status"
|
209
|
+
begin
|
210
|
+
Process.kill 0, @pid
|
211
|
+
puts "Puma is started"
|
212
|
+
rescue Errno::ESRCH
|
213
|
+
raise "Puma is not running"
|
214
|
+
end
|
215
|
+
|
216
|
+
return
|
217
|
+
|
204
218
|
else
|
205
|
-
message "Puma is started"
|
206
219
|
return
|
207
220
|
end
|
208
221
|
|
@@ -218,7 +231,7 @@ module Puma
|
|
218
231
|
end
|
219
232
|
|
220
233
|
def run
|
221
|
-
start if @command == "start"
|
234
|
+
return start if @command == "start"
|
222
235
|
|
223
236
|
prepare_configuration
|
224
237
|
|
@@ -242,7 +255,7 @@ module Puma
|
|
242
255
|
run_args += ["-S", @state] if @state
|
243
256
|
run_args += ["-q"] if @quiet
|
244
257
|
run_args += ["--pidfile", @pidfile] if @pidfile
|
245
|
-
run_args += ["--control", @control_url] if @control_url
|
258
|
+
run_args += ["--control-url", @control_url] if @control_url
|
246
259
|
run_args += ["--control-token", @control_auth_token] if @control_auth_token
|
247
260
|
run_args += ["-C", @config_file] if @config_file
|
248
261
|
|
data/lib/puma/convenient.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puma/launcher'
|
2
4
|
require 'puma/configuration'
|
3
5
|
|
4
6
|
module Puma
|
5
7
|
def self.run(opts={})
|
6
|
-
cfg = Puma::Configuration.new do |
|
8
|
+
cfg = Puma::Configuration.new do |user_config|
|
7
9
|
if port = opts[:port]
|
8
|
-
|
10
|
+
user_config.port port
|
9
11
|
end
|
10
12
|
|
11
|
-
|
13
|
+
user_config.quiet
|
12
14
|
|
13
15
|
yield c
|
14
16
|
end
|
data/lib/puma/daemon_ext.rb
CHANGED
data/lib/puma/delegation.rb
CHANGED
data/lib/puma/detect.rb
CHANGED
data/lib/puma/dsl.rb
CHANGED
@@ -1,20 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puma/const'
|
4
|
+
|
1
5
|
module Puma
|
2
|
-
# The methods that are available for use inside the
|
6
|
+
# The methods that are available for use inside the configuration file.
|
7
|
+
# These same methods are used in Puma cli and the rack handler
|
8
|
+
# internally.
|
9
|
+
#
|
10
|
+
# Used manually (via CLI class):
|
11
|
+
#
|
12
|
+
# config = Configuration.new({}) do |user_config|
|
13
|
+
# user_config.port 3001
|
14
|
+
# end
|
15
|
+
# config.load
|
16
|
+
#
|
17
|
+
# puts config.options[:binds]
|
18
|
+
# "tcp://127.0.0.1:3001"
|
3
19
|
#
|
20
|
+
# Used to load file:
|
21
|
+
#
|
22
|
+
# $ cat puma_config.rb
|
23
|
+
# port 3002
|
24
|
+
#
|
25
|
+
# config = Configuration.new(config_file: "puma_config.rb")
|
26
|
+
# config.load
|
27
|
+
#
|
28
|
+
# puts config.options[:binds]
|
29
|
+
# # => "tcp://127.0.0.1:3002"
|
30
|
+
#
|
31
|
+
# You can also find many examples being used by the test suite in
|
32
|
+
# +test/config+.
|
4
33
|
class DSL
|
5
34
|
include ConfigDefault
|
6
35
|
|
7
|
-
def self.load(options, cfg, path)
|
8
|
-
d = new(options, cfg)
|
9
|
-
d._load_from(path)
|
10
|
-
|
11
|
-
options
|
12
|
-
ensure
|
13
|
-
d._offer_plugins
|
14
|
-
end
|
15
|
-
|
16
36
|
def initialize(options, config)
|
17
|
-
@config
|
37
|
+
@config = config
|
18
38
|
@options = options
|
19
39
|
|
20
40
|
@plugins = []
|
@@ -40,34 +60,16 @@ module Puma
|
|
40
60
|
@plugins.clear
|
41
61
|
end
|
42
62
|
|
43
|
-
def
|
44
|
-
|
45
|
-
ensure
|
46
|
-
_offer_plugins
|
63
|
+
def set_default_host(host)
|
64
|
+
@options[:default_host] = host
|
47
65
|
end
|
48
66
|
|
49
|
-
def
|
50
|
-
|
67
|
+
def default_host
|
68
|
+
@options[:default_host] || Configuration::DefaultTCPHost
|
51
69
|
end
|
52
70
|
|
53
|
-
|
54
|
-
|
55
|
-
# current config file.
|
56
|
-
#
|
57
|
-
def import(file)
|
58
|
-
if File.extname(file) == ""
|
59
|
-
file += ".rb"
|
60
|
-
end
|
61
|
-
|
62
|
-
if file[0,1] == "/"
|
63
|
-
path = file
|
64
|
-
elsif @path
|
65
|
-
path = File.join File.dirname(@path), file
|
66
|
-
else
|
67
|
-
raise "No original configuration path to import relative to"
|
68
|
-
end
|
69
|
-
|
70
|
-
DSL.new(@options, @config)._load_from(path)
|
71
|
+
def inject(&blk)
|
72
|
+
instance_eval(&blk)
|
71
73
|
end
|
72
74
|
|
73
75
|
def get(key,default=nil)
|
@@ -80,9 +82,22 @@ module Puma
|
|
80
82
|
@plugins << @config.load_plugin(name)
|
81
83
|
end
|
82
84
|
|
83
|
-
# Use
|
84
|
-
# be the
|
85
|
+
# Use an object or block as the rack application. This allows the
|
86
|
+
# configuration file to be the application itself.
|
87
|
+
#
|
88
|
+
# @example
|
89
|
+
# app do |env|
|
90
|
+
# body = 'Hello, World!'
|
85
91
|
#
|
92
|
+
# [
|
93
|
+
# 200,
|
94
|
+
# {
|
95
|
+
# 'Content-Type' => 'text/plain',
|
96
|
+
# 'Content-Length' => body.length.to_s
|
97
|
+
# },
|
98
|
+
# [body]
|
99
|
+
# ]
|
100
|
+
# end
|
86
101
|
def app(obj=nil, &block)
|
87
102
|
obj ||= block
|
88
103
|
|
@@ -91,9 +106,20 @@ module Puma
|
|
91
106
|
@options[:app] = obj
|
92
107
|
end
|
93
108
|
|
94
|
-
# Start the Puma control rack
|
95
|
-
# with to control the main server.
|
109
|
+
# Start the Puma control rack application on +url+. This application can
|
110
|
+
# be communicated with to control the main server. Additionally, you can
|
111
|
+
# provide an authentication token, so all requests to the control server
|
112
|
+
# will need to include that token as a query parameter. This allows for
|
113
|
+
# simple authentication.
|
96
114
|
#
|
115
|
+
# Check out {Puma::App::Status} to see what the app has available.
|
116
|
+
#
|
117
|
+
# @example
|
118
|
+
# activate_control_app 'unix:///var/run/pumactl.sock'
|
119
|
+
# @example
|
120
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
|
121
|
+
# @example
|
122
|
+
# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
|
97
123
|
def activate_control_app(url="auto", opts={})
|
98
124
|
if url == "auto"
|
99
125
|
path = Configuration.temp_path
|
@@ -104,7 +130,12 @@ module Puma
|
|
104
130
|
end
|
105
131
|
|
106
132
|
if opts[:no_token]
|
107
|
-
|
133
|
+
# We need to use 'none' rather than :none because this value will be
|
134
|
+
# passed on to an instance of OptionParser, which doesn't support
|
135
|
+
# symbols as option values.
|
136
|
+
#
|
137
|
+
# See: https://github.com/puma/puma/issues/1193#issuecomment-305995488
|
138
|
+
auth_token = 'none'
|
108
139
|
else
|
109
140
|
auth_token = opts[:auth_token]
|
110
141
|
auth_token ||= Configuration.random_token
|
@@ -115,53 +146,99 @@ module Puma
|
|
115
146
|
end
|
116
147
|
|
117
148
|
# Load additional configuration from a file
|
149
|
+
# Files get loaded later via Configuration#load
|
118
150
|
def load(file)
|
119
|
-
|
151
|
+
@options[:config_files] ||= []
|
152
|
+
@options[:config_files] << file
|
120
153
|
end
|
121
154
|
|
122
|
-
# Bind the server to +url+. tcp:// and
|
123
|
-
# protocols.
|
155
|
+
# Bind the server to +url+. "tcp://", "unix://" and "ssl://" are the only
|
156
|
+
# accepted protocols. Multiple urls can be bound to, calling `bind` does
|
157
|
+
# not overwrite previous bindings.
|
158
|
+
#
|
159
|
+
# The default is "tcp://0.0.0.0:9292".
|
124
160
|
#
|
161
|
+
# You can use query parameters within the url to specify options:
|
162
|
+
#
|
163
|
+
# - Set the socket backlog depth with +backlog+, default is 1024.
|
164
|
+
# - Set up an SSL certificate with +key+ & +cert+.
|
165
|
+
# - Set whether to optimize for low latency instead of throughput with
|
166
|
+
# +low_latency+, default is to optimize for low latency. This is done
|
167
|
+
# via +Socket::TCP_NODELAY+.
|
168
|
+
# - Set socket permissions with +umask+.
|
169
|
+
#
|
170
|
+
# @example Backlog depth
|
171
|
+
# bind 'unix:///var/run/puma.sock?backlog=512'
|
172
|
+
# @example SSL cert
|
173
|
+
# bind 'ssl://127.0.0.1:9292?key=key.key&cert=cert.pem'
|
174
|
+
# @example Disable optimization for low latency
|
175
|
+
# bind 'tcp://0.0.0.0:9292?low_latency=false'
|
176
|
+
# @example Socket permissions
|
177
|
+
# bind 'unix:///var/run/puma.sock?umask=0111'
|
125
178
|
def bind(url)
|
126
|
-
|
179
|
+
@options[:binds] ||= []
|
180
|
+
@options[:binds] << url
|
181
|
+
end
|
182
|
+
|
183
|
+
def clear_binds!
|
184
|
+
@options[:binds] = []
|
127
185
|
end
|
128
186
|
|
129
187
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
130
188
|
#
|
189
|
+
# @example
|
190
|
+
# port 9292
|
131
191
|
def port(port, host=nil)
|
132
|
-
host ||=
|
192
|
+
host ||= default_host
|
133
193
|
bind "tcp://#{host}:#{port}"
|
134
194
|
end
|
135
195
|
|
136
|
-
# Define how long persistent connections can be idle before
|
137
|
-
# them
|
138
|
-
#
|
196
|
+
# Define how long persistent connections can be idle before Puma closes
|
197
|
+
# them.
|
139
198
|
def persistent_timeout(seconds)
|
140
|
-
@options[:persistent_timeout] = seconds
|
199
|
+
@options[:persistent_timeout] = Integer(seconds)
|
200
|
+
end
|
201
|
+
|
202
|
+
# Define how long the tcp socket stays open, if no data has been received.
|
203
|
+
def first_data_timeout(seconds)
|
204
|
+
@options[:first_data_timeout] = Integer(seconds)
|
141
205
|
end
|
142
206
|
|
143
207
|
# Work around leaky apps that leave garbage in Thread locals
|
144
|
-
# across requests
|
145
|
-
#
|
208
|
+
# across requests.
|
146
209
|
def clean_thread_locals(which=true)
|
147
210
|
@options[:clean_thread_locals] = which
|
148
211
|
end
|
149
212
|
|
150
|
-
# Daemonize the server into the background.
|
151
|
-
# this
|
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
|
152
223
|
def daemonize(which=true)
|
153
224
|
@options[:daemon] = which
|
154
225
|
end
|
155
226
|
|
156
227
|
# When shutting down, drain the accept socket of pending
|
157
|
-
# connections and
|
228
|
+
# connections and process them. This loops over the accept
|
158
229
|
# socket until there are no more read events and then stops
|
159
230
|
# looking and waits for the requests to finish.
|
160
231
|
def drain_on_shutdown(which=true)
|
161
232
|
@options[:drain_on_shutdown] = which
|
162
233
|
end
|
163
234
|
|
164
|
-
# Set the environment in which the
|
235
|
+
# Set the environment in which the rack's app will run. The value must be
|
236
|
+
# a string.
|
237
|
+
#
|
238
|
+
# The default is "development".
|
239
|
+
#
|
240
|
+
# @example
|
241
|
+
# environment 'production'
|
165
242
|
def environment(environment)
|
166
243
|
@options[:environment] = environment
|
167
244
|
end
|
@@ -187,29 +264,41 @@ module Puma
|
|
187
264
|
end
|
188
265
|
|
189
266
|
# Code to run before doing a restart. This code should
|
190
|
-
# close
|
267
|
+
# close log files, database connections, etc.
|
191
268
|
#
|
192
269
|
# This can be called multiple times to add code each time.
|
193
270
|
#
|
271
|
+
# @example
|
272
|
+
# on_restart do
|
273
|
+
# puts 'On restart...'
|
274
|
+
# end
|
194
275
|
def on_restart(&block)
|
195
|
-
|
276
|
+
@options[:on_restart] ||= []
|
277
|
+
@options[:on_restart] << block
|
196
278
|
end
|
197
279
|
|
198
|
-
# Command to use to restart
|
199
|
-
# load
|
200
|
-
# to
|
280
|
+
# Command to use to restart Puma. This should be just how to
|
281
|
+
# load Puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
|
282
|
+
# to Puma, as those are the same as the original process.
|
201
283
|
#
|
284
|
+
# @example
|
285
|
+
# restart_command '/u/app/lolcat/bin/restart_puma'
|
202
286
|
def restart_command(cmd)
|
203
287
|
@options[:restart_cmd] = cmd.to_s
|
204
288
|
end
|
205
289
|
|
206
|
-
# Store the pid of the server in the file at
|
290
|
+
# Store the pid of the server in the file at "path".
|
291
|
+
#
|
292
|
+
# @example
|
293
|
+
# pidfile '/u/apps/lolcat/tmp/pids/puma.pid'
|
207
294
|
def pidfile(path)
|
208
295
|
@options[:pidfile] = path.to_s
|
209
296
|
end
|
210
297
|
|
211
|
-
# Disable request logging.
|
298
|
+
# Disable request logging, if this isn't used it'll be enabled by default.
|
212
299
|
#
|
300
|
+
# @example
|
301
|
+
# quiet
|
213
302
|
def quiet(which=true)
|
214
303
|
@options[:log_requests] = !which
|
215
304
|
end
|
@@ -228,6 +317,10 @@ module Puma
|
|
228
317
|
|
229
318
|
# Load +path+ as a rackup file.
|
230
319
|
#
|
320
|
+
# The default is "config.ru".
|
321
|
+
#
|
322
|
+
# @example
|
323
|
+
# rackup '/u/apps/lolcat/config.ru'
|
231
324
|
def rackup(path)
|
232
325
|
@options[:rackup] = path.to_s
|
233
326
|
end
|
@@ -238,16 +331,36 @@ module Puma
|
|
238
331
|
@options[:mode] = :tcp
|
239
332
|
end
|
240
333
|
|
241
|
-
|
334
|
+
def early_hints(answer=true)
|
335
|
+
@options[:early_hints] = answer
|
336
|
+
end
|
337
|
+
|
338
|
+
# Redirect STDOUT and STDERR to files specified. The +append+ parameter
|
339
|
+
# specifies whether the output is appended, the default is +false+.
|
340
|
+
#
|
341
|
+
# @example
|
342
|
+
# stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr'
|
343
|
+
# @example
|
344
|
+
# stdout_redirect '/app/lolcat/log/stdout', '/app/lolcat/log/stderr', true
|
242
345
|
def stdout_redirect(stdout=nil, stderr=nil, append=false)
|
243
346
|
@options[:redirect_stdout] = stdout
|
244
347
|
@options[:redirect_stderr] = stderr
|
245
348
|
@options[:redirect_append] = append
|
246
349
|
end
|
247
350
|
|
351
|
+
def log_formatter(&block)
|
352
|
+
@options[:log_formatter] = block
|
353
|
+
end
|
354
|
+
|
248
355
|
# Configure +min+ to be the minimum number of threads to use to answer
|
249
356
|
# requests and +max+ the maximum.
|
250
357
|
#
|
358
|
+
# The default is "0, 16".
|
359
|
+
#
|
360
|
+
# @example
|
361
|
+
# threads 0, 16
|
362
|
+
# @example
|
363
|
+
# threads 5, 5
|
251
364
|
def threads(min, max)
|
252
365
|
min = Integer(min)
|
253
366
|
max = Integer(max)
|
@@ -263,84 +376,162 @@ module Puma
|
|
263
376
|
@options[:max_threads] = max
|
264
377
|
end
|
265
378
|
|
379
|
+
# Instead of "bind 'ssl://127.0.0.1:9292?key=key_path&cert=cert_path'" you
|
380
|
+
# can also use the "ssl_bind" option.
|
381
|
+
#
|
382
|
+
# @example
|
383
|
+
# ssl_bind '127.0.0.1', '9292', {
|
384
|
+
# cert: path_to_cert,
|
385
|
+
# key: path_to_key,
|
386
|
+
# ssl_cipher_filter: cipher_filter, # optional
|
387
|
+
# verify_mode: verify_mode, # default 'none'
|
388
|
+
# }
|
389
|
+
# @example For JRuby additional keys are required: keystore & keystore_pass.
|
390
|
+
# ssl_bind '127.0.0.1', '9292', {
|
391
|
+
# cert: path_to_cert,
|
392
|
+
# key: path_to_key,
|
393
|
+
# ssl_cipher_filter: cipher_filter, # optional
|
394
|
+
# verify_mode: verify_mode, # default 'none'
|
395
|
+
# keystore: path_to_keystore,
|
396
|
+
# keystore_pass: password
|
397
|
+
# }
|
266
398
|
def ssl_bind(host, port, opts)
|
267
399
|
verify = opts.fetch(:verify_mode, 'none')
|
400
|
+
no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
|
401
|
+
no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
|
402
|
+
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
268
403
|
|
269
404
|
if defined?(JRUBY_VERSION)
|
270
405
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
271
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}"
|
406
|
+
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}"
|
272
407
|
else
|
273
|
-
|
408
|
+
ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
|
409
|
+
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}"
|
274
410
|
end
|
275
411
|
end
|
276
412
|
|
277
413
|
# Use +path+ as the file to store the server info state. This is
|
278
|
-
# used by pumactl to query and control the server.
|
414
|
+
# used by +pumactl+ to query and control the server.
|
279
415
|
#
|
416
|
+
# @example
|
417
|
+
# state_path '/u/apps/lolcat/tmp/pids/puma.state'
|
280
418
|
def state_path(path)
|
281
419
|
@options[:state] = path.to_s
|
282
420
|
end
|
283
421
|
|
284
|
-
#
|
422
|
+
# How many worker processes to run. Typically this is set to
|
423
|
+
# to the number of available cores.
|
285
424
|
#
|
425
|
+
# The default is 0.
|
426
|
+
#
|
427
|
+
# @note Cluster mode only.
|
286
428
|
def workers(count)
|
287
429
|
@options[:workers] = count.to_i
|
288
430
|
end
|
289
431
|
|
290
|
-
#
|
432
|
+
# Code to run immediately before master process
|
291
433
|
# forks workers (once on boot). These hooks can block if necessary
|
292
|
-
# to wait for background operations unknown to
|
434
|
+
# to wait for background operations unknown to Puma to finish before
|
293
435
|
# the process terminates.
|
294
|
-
# This can be used to close any connections to remote servers (database,
|
295
|
-
# that were opened when preloading the code
|
436
|
+
# This can be used to close any connections to remote servers (database,
|
437
|
+
# Redis, ...) that were opened when preloading the code.
|
296
438
|
#
|
297
|
-
# This can be called multiple times to add hooks.
|
439
|
+
# This can be called multiple times to add several hooks.
|
298
440
|
#
|
441
|
+
# @note Cluster mode only.
|
442
|
+
# @example
|
443
|
+
# before_fork do
|
444
|
+
# puts "Starting workers..."
|
445
|
+
# end
|
299
446
|
def before_fork(&block)
|
300
|
-
|
447
|
+
@options[:before_fork] ||= []
|
448
|
+
@options[:before_fork] << block
|
301
449
|
end
|
302
450
|
|
303
|
-
#
|
451
|
+
# Code to run in a worker when it boots to setup
|
304
452
|
# the process before booting the app.
|
305
453
|
#
|
306
|
-
# This can be called multiple times to add hooks.
|
454
|
+
# This can be called multiple times to add several hooks.
|
307
455
|
#
|
456
|
+
# @note Cluster mode only.
|
457
|
+
# @example
|
458
|
+
# on_worker_fork do
|
459
|
+
# puts 'Before worker fork...'
|
460
|
+
# end
|
308
461
|
def on_worker_boot(&block)
|
309
|
-
|
462
|
+
@options[:before_worker_boot] ||= []
|
463
|
+
@options[:before_worker_boot] << block
|
310
464
|
end
|
311
465
|
|
312
|
-
#
|
466
|
+
# Code to run immediately before a worker shuts
|
313
467
|
# down (after it has finished processing HTTP requests). These hooks
|
314
468
|
# can block if necessary to wait for background operations unknown
|
315
|
-
# to
|
469
|
+
# to Puma to finish before the process terminates.
|
316
470
|
#
|
317
|
-
# This can be called multiple times to add hooks.
|
471
|
+
# This can be called multiple times to add several hooks.
|
318
472
|
#
|
473
|
+
# @note Cluster mode only.
|
474
|
+
# @example
|
475
|
+
# on_worker_shutdown do
|
476
|
+
# puts 'On worker shutdown...'
|
477
|
+
# end
|
319
478
|
def on_worker_shutdown(&block)
|
320
|
-
|
479
|
+
@options[:before_worker_shutdown] ||= []
|
480
|
+
@options[:before_worker_shutdown] << block
|
321
481
|
end
|
322
482
|
|
323
|
-
#
|
324
|
-
#
|
483
|
+
# Code to run in the master right before a worker is started. The worker's
|
484
|
+
# index is passed as an argument.
|
325
485
|
#
|
326
|
-
# This can be called multiple times to add hooks.
|
486
|
+
# This can be called multiple times to add several hooks.
|
327
487
|
#
|
488
|
+
# @note Cluster mode only.
|
489
|
+
# @example
|
490
|
+
# on_worker_fork do
|
491
|
+
# puts 'Before worker fork...'
|
492
|
+
# end
|
328
493
|
def on_worker_fork(&block)
|
329
|
-
|
494
|
+
@options[:before_worker_fork] ||= []
|
495
|
+
@options[:before_worker_fork] << block
|
330
496
|
end
|
331
497
|
|
332
|
-
#
|
333
|
-
#
|
498
|
+
# Code to run in the master after a worker has been started. The worker's
|
499
|
+
# index is passed as an argument.
|
334
500
|
#
|
335
|
-
# This
|
501
|
+
# This is called everytime a worker is to be started.
|
336
502
|
#
|
503
|
+
# @note Cluster mode only.
|
504
|
+
# @example
|
505
|
+
# after_worker_fork do
|
506
|
+
# puts 'After worker fork...'
|
507
|
+
# end
|
337
508
|
def after_worker_fork(&block)
|
338
|
-
|
509
|
+
@options[:after_worker_fork] ||= []
|
510
|
+
@options[:after_worker_fork] = block
|
339
511
|
end
|
340
512
|
|
341
513
|
alias_method :after_worker_boot, :after_worker_fork
|
342
514
|
|
515
|
+
# Code to run out-of-band when the worker is idle.
|
516
|
+
# These hooks run immediately after a request has finished
|
517
|
+
# processing and there are no busy threads on the worker.
|
518
|
+
# The worker doesn't accept new requests until this code finishes.
|
519
|
+
#
|
520
|
+
# This hook is useful for running out-of-band garbage collection
|
521
|
+
# or scheduling asynchronous tasks to execute after a response.
|
522
|
+
#
|
523
|
+
# This can be called multiple times to add several hooks.
|
524
|
+
def out_of_band(&block)
|
525
|
+
@options[:out_of_band] ||= []
|
526
|
+
@options[:out_of_band] << block
|
527
|
+
end
|
528
|
+
|
343
529
|
# The directory to operate out of.
|
530
|
+
#
|
531
|
+
# The default is the current directory.
|
532
|
+
#
|
533
|
+
# @example
|
534
|
+
# directory '/u/apps/lolcat'
|
344
535
|
def directory(dir)
|
345
536
|
@options[:directory] = dir.to_s
|
346
537
|
end
|
@@ -351,22 +542,28 @@ module Puma
|
|
351
542
|
directory dir
|
352
543
|
end
|
353
544
|
|
354
|
-
# Run the app as a raw TCP app instead of an HTTP rack app
|
545
|
+
# Run the app as a raw TCP app instead of an HTTP rack app.
|
355
546
|
def tcp_mode
|
356
547
|
@options[:mode] = :tcp
|
357
548
|
end
|
358
549
|
|
359
|
-
#
|
360
|
-
#
|
361
|
-
# with using the phased restart feature, you can't use both.
|
550
|
+
# Preload the application before starting the workers; this conflicts with
|
551
|
+
# phased restart feature. This is off by default.
|
362
552
|
#
|
553
|
+
# @note Cluster mode only.
|
554
|
+
# @example
|
555
|
+
# preload_app!
|
363
556
|
def preload_app!(answer=true)
|
364
557
|
@options[:preload_app] = answer
|
365
558
|
end
|
366
559
|
|
367
|
-
# Use +obj+ or +block+ as the low level error handler. This allows
|
368
|
-
# change the default error on the server.
|
560
|
+
# Use +obj+ or +block+ as the low level error handler. This allows the
|
561
|
+
# configuration file to change the default error on the server.
|
369
562
|
#
|
563
|
+
# @example
|
564
|
+
# lowlevel_error_handler do |err|
|
565
|
+
# [200, {}, ["error page"]]
|
566
|
+
# end
|
370
567
|
def lowlevel_error_handler(obj=nil, &block)
|
371
568
|
obj ||= block
|
372
569
|
raise "Provide either a #call'able or a block" unless obj
|
@@ -376,40 +573,84 @@ module Puma
|
|
376
573
|
# This option is used to allow your app and its gems to be
|
377
574
|
# properly reloaded when not using preload.
|
378
575
|
#
|
379
|
-
# When set, if
|
576
|
+
# When set, if Puma detects that it's been invoked in the
|
380
577
|
# context of Bundler, it will cleanup the environment and
|
381
578
|
# re-run itself outside the Bundler environment, but directly
|
382
579
|
# using the files that Bundler has setup.
|
383
580
|
#
|
384
|
-
# This means that
|
581
|
+
# This means that Puma is now decoupled from your Bundler
|
385
582
|
# context and when each worker loads, it will be loading a
|
386
583
|
# new Bundler context and thus can float around as the release
|
387
584
|
# dictates.
|
585
|
+
#
|
586
|
+
# @note This is incompatible with +preload_app!+.
|
388
587
|
def prune_bundler(answer=true)
|
389
588
|
@options[:prune_bundler] = answer
|
390
589
|
end
|
391
590
|
|
392
|
-
#
|
591
|
+
# By default, Puma will raise SignalException when SIGTERM is received. In
|
592
|
+
# environments where SIGTERM is something expected, you can suppress these
|
593
|
+
# with this option.
|
594
|
+
#
|
595
|
+
# This can be useful for example in Kubernetes, where rolling restart is
|
596
|
+
# guaranteed usually on infrastructure level.
|
597
|
+
#
|
598
|
+
# @example
|
599
|
+
# raise_exception_on_sigterm false
|
600
|
+
def raise_exception_on_sigterm(answer=true)
|
601
|
+
@options[:raise_exception_on_sigterm] = answer
|
602
|
+
end
|
603
|
+
|
604
|
+
# Additional text to display in process listing.
|
605
|
+
#
|
606
|
+
# If you do not specify a tag, Puma will infer it. If you do not want Puma
|
607
|
+
# to add a tag, use an empty string.
|
608
|
+
#
|
609
|
+
# @example
|
610
|
+
# tag 'app name'
|
611
|
+
# @example
|
612
|
+
# tag ''
|
393
613
|
def tag(string)
|
394
614
|
@options[:tag] = string.to_s
|
395
615
|
end
|
396
616
|
|
397
|
-
#
|
398
|
-
#
|
399
|
-
#
|
400
|
-
#
|
617
|
+
# Verifies that all workers have checked in to the master process within
|
618
|
+
# the given timeout. If not the worker process will be restarted. This is
|
619
|
+
# not a request timeout, it is to protect against a hung or dead process.
|
620
|
+
# Setting this value will not protect against slow requests.
|
621
|
+
#
|
622
|
+
# The minimum value is 6 seconds, the default value is 60 seconds.
|
623
|
+
#
|
624
|
+
# @note Cluster mode only.
|
625
|
+
# @example
|
626
|
+
# worker_timeout 60
|
401
627
|
def worker_timeout(timeout)
|
628
|
+
timeout = Integer(timeout)
|
629
|
+
min = Const::WORKER_CHECK_INTERVAL
|
630
|
+
|
631
|
+
if timeout <= min
|
632
|
+
raise "The minimum worker_timeout must be greater than the worker reporting interval (#{min})"
|
633
|
+
end
|
634
|
+
|
402
635
|
@options[:worker_timeout] = timeout
|
403
636
|
end
|
404
637
|
|
405
|
-
#
|
638
|
+
# Change the default worker timeout for booting.
|
639
|
+
#
|
640
|
+
# If unspecified, this defaults to the value of worker_timeout.
|
641
|
+
#
|
642
|
+
# @note Cluster mode only.
|
643
|
+
# @example:
|
644
|
+
# worker_boot_timeout 60
|
406
645
|
def worker_boot_timeout(timeout)
|
407
|
-
@options[:worker_boot_timeout] = timeout
|
646
|
+
@options[:worker_boot_timeout] = Integer(timeout)
|
408
647
|
end
|
409
648
|
|
410
|
-
#
|
649
|
+
# Set the timeout for worker shutdown
|
650
|
+
#
|
651
|
+
# @note Cluster mode only.
|
411
652
|
def worker_shutdown_timeout(timeout)
|
412
|
-
@options[:worker_shutdown_timeout] = timeout
|
653
|
+
@options[:worker_shutdown_timeout] = Integer(timeout)
|
413
654
|
end
|
414
655
|
|
415
656
|
# When set to true (the default), workers accept all requests
|
@@ -424,7 +665,7 @@ module Puma
|
|
424
665
|
# Note that setting this to false disables HTTP keepalive and
|
425
666
|
# slow clients will occupy a handler thread while the request
|
426
667
|
# is being sent. A reverse proxy, such as nginx, can handle
|
427
|
-
# slow clients and queue requests before they reach
|
668
|
+
# slow clients and queue requests before they reach Puma.
|
428
669
|
def queue_requests(answer=true)
|
429
670
|
@options[:queue_requests] = answer
|
430
671
|
end
|
@@ -453,7 +694,7 @@ module Puma
|
|
453
694
|
# is used, allowing headers such as X-Forwarded-For
|
454
695
|
# to be used as well.
|
455
696
|
# * Any string - this allows you to hardcode remote address to any value
|
456
|
-
# you wish. Because
|
697
|
+
# you wish. Because Puma never uses this field anyway, it's
|
457
698
|
# format is entirely in your hands.
|
458
699
|
def set_remote_address(val=:socket)
|
459
700
|
case val
|
@@ -468,7 +709,7 @@ module Puma
|
|
468
709
|
when Hash
|
469
710
|
if hdr = val[:header]
|
470
711
|
@options[:remote_address] = :header
|
471
|
-
@options[:remote_address_header] = "HTTP_" + hdr.upcase.
|
712
|
+
@options[:remote_address_header] = "HTTP_" + hdr.upcase.tr("-", "_")
|
472
713
|
else
|
473
714
|
raise "Invalid value for set_remote_address - #{val.inspect}"
|
474
715
|
end
|
@@ -477,10 +718,5 @@ module Puma
|
|
477
718
|
end
|
478
719
|
end
|
479
720
|
|
480
|
-
private
|
481
|
-
|
482
|
-
def _ary(key)
|
483
|
-
(@options.cur[key] ||= [])
|
484
|
-
end
|
485
721
|
end
|
486
722
|
end
|