puma 3.4.0 → 3.12.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.

Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +356 -74
  3. data/README.md +143 -227
  4. data/docs/architecture.md +36 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +1 -1
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/plugins.md +28 -0
  10. data/docs/restart.md +39 -0
  11. data/docs/signals.md +56 -3
  12. data/docs/systemd.md +124 -22
  13. data/ext/puma_http11/extconf.rb +2 -0
  14. data/ext/puma_http11/http11_parser.c +291 -447
  15. data/ext/puma_http11/http11_parser.h +1 -0
  16. data/ext/puma_http11/http11_parser.rl +10 -9
  17. data/ext/puma_http11/http11_parser_common.rl +1 -1
  18. data/ext/puma_http11/io_buffer.c +7 -7
  19. data/ext/puma_http11/mini_ssl.c +67 -6
  20. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +76 -94
  21. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +15 -2
  22. data/ext/puma_http11/puma_http11.c +1 -0
  23. data/lib/puma.rb +13 -5
  24. data/lib/puma/app/status.rb +8 -0
  25. data/lib/puma/binder.rb +46 -21
  26. data/lib/puma/cli.rb +49 -33
  27. data/lib/puma/client.rb +149 -4
  28. data/lib/puma/cluster.rb +55 -13
  29. data/lib/puma/commonlogger.rb +19 -20
  30. data/lib/puma/compat.rb +3 -7
  31. data/lib/puma/configuration.rb +136 -131
  32. data/lib/puma/const.rb +19 -37
  33. data/lib/puma/control_cli.rb +38 -35
  34. data/lib/puma/convenient.rb +3 -3
  35. data/lib/puma/detect.rb +3 -1
  36. data/lib/puma/dsl.rb +86 -57
  37. data/lib/puma/events.rb +17 -13
  38. data/lib/puma/io_buffer.rb +1 -1
  39. data/lib/puma/jruby_restart.rb +0 -1
  40. data/lib/puma/launcher.rb +61 -30
  41. data/lib/puma/minissl.rb +85 -4
  42. data/lib/puma/null_io.rb +6 -13
  43. data/lib/puma/plugin.rb +12 -1
  44. data/lib/puma/plugin/tmp_restart.rb +1 -2
  45. data/lib/puma/rack/builder.rb +3 -0
  46. data/lib/puma/rack/urlmap.rb +9 -8
  47. data/lib/puma/reactor.rb +144 -0
  48. data/lib/puma/runner.rb +27 -1
  49. data/lib/puma/server.rb +135 -33
  50. data/lib/puma/single.rb +17 -3
  51. data/lib/puma/tcp_logger.rb +8 -1
  52. data/lib/puma/thread_pool.rb +70 -20
  53. data/lib/puma/util.rb +1 -5
  54. data/lib/rack/handler/puma.rb +58 -17
  55. data/tools/jungle/README.md +12 -2
  56. data/tools/jungle/init.d/README.md +9 -2
  57. data/tools/jungle/init.d/puma +85 -58
  58. data/tools/jungle/init.d/run-puma +16 -1
  59. data/tools/jungle/rc.d/README.md +74 -0
  60. data/tools/jungle/rc.d/puma +61 -0
  61. data/tools/jungle/rc.d/puma.conf +10 -0
  62. data/tools/jungle/upstart/puma.conf +1 -1
  63. data/tools/trickletest.rb +1 -1
  64. metadata +22 -94
  65. data/Gemfile +0 -13
  66. data/Manifest.txt +0 -78
  67. data/Rakefile +0 -158
  68. data/docs/config.md +0 -0
  69. data/lib/puma/rack/backports/uri/common_18.rb +0 -59
  70. data/lib/puma/rack/backports/uri/common_192.rb +0 -55
  71. data/puma.gemspec +0 -52
@@ -53,6 +53,8 @@ module Puma
53
53
  415 => 'Unsupported Media Type',
54
54
  416 => 'Range Not Satisfiable',
55
55
  417 => 'Expectation Failed',
56
+ 418 => 'I\'m A Teapot',
57
+ 421 => 'Misdirected Request',
56
58
  422 => 'Unprocessable Entity',
57
59
  423 => 'Locked',
58
60
  424 => 'Failed Dependency',
@@ -60,6 +62,7 @@ module Puma
60
62
  428 => 'Precondition Required',
61
63
  429 => 'Too Many Requests',
62
64
  431 => 'Request Header Fields Too Large',
65
+ 451 => 'Unavailable For Legal Reasons',
63
66
  500 => 'Internal Server Error',
64
67
  501 => 'Not Implemented',
65
68
  502 => 'Bad Gateway',
@@ -73,19 +76,14 @@ module Puma
73
76
  511 => 'Network Authentication Required'
74
77
  }
75
78
 
76
- SYMBOL_TO_STATUS_CODE = Hash[*HTTP_STATUS_CODES.map { |code, message|
77
- [message.downcase.gsub(/\s|-|'/, '_').to_sym, code]
78
- }.flatten]
79
-
80
79
  # For some HTTP status codes the client only expects headers.
81
80
  #
82
81
 
83
- no_body = {}
84
- ((100..199).to_a << 204 << 205 << 304).each do |code|
85
- no_body[code] = true
86
- end
87
-
88
- STATUS_WITH_NO_ENTITY_BODY = no_body
82
+ STATUS_WITH_NO_ENTITY_BODY = {
83
+ 204 => true,
84
+ 205 => true,
85
+ 304 => true
86
+ }
89
87
 
90
88
  # Frequently used constants when constructing requests or responses. Many times
91
89
  # the constant just refers to a string with the same contents. Using these constants
@@ -100,10 +98,10 @@ module Puma
100
98
  # too taxing on performance.
101
99
  module Const
102
100
 
103
- PUMA_VERSION = VERSION = "3.4.0".freeze
104
- CODE_NAME = "Owl Bowl Brawl".freeze
101
+ PUMA_VERSION = VERSION = "3.12.0".freeze
102
+ CODE_NAME = "Llamas in Pajamas".freeze
105
103
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
-
104
+
107
105
  FAST_TRACK_KA_TIMEOUT = 0.2
108
106
 
109
107
  # The default number of seconds for another request within a persistent
@@ -118,15 +116,6 @@ module Puma
118
116
  # sending data back
119
117
  WRITE_TIMEOUT = 10
120
118
 
121
- # How long, after raising the ForceShutdown of a thread during
122
- # forced shutdown mode, to wait for the thread to try and finish
123
- # up it's work before leaving the thread to die on the vine.
124
- SHUTDOWN_GRACE_TIME = 5 # seconds
125
-
126
- DATE = "Date".freeze
127
-
128
- SCRIPT_NAME = "SCRIPT_NAME".freeze
129
-
130
119
  # The original URI requested by the client.
131
120
  REQUEST_URI= 'REQUEST_URI'.freeze
132
121
  REQUEST_PATH = 'REQUEST_PATH'.freeze
@@ -163,26 +152,12 @@ module Puma
163
152
  # Maximum request body size before it is moved out of memory and into a tempfile for reading.
164
153
  MAX_BODY = MAX_HEADER
165
154
 
166
- # A frozen format for this is about 15% faster
167
- STATUS_FORMAT = "HTTP/1.1 %d %s\r\nConnection: close\r\n".freeze
168
-
169
- CONTENT_TYPE = "Content-Type".freeze
170
-
171
- LAST_MODIFIED = "Last-Modified".freeze
172
- ETAG = "ETag".freeze
173
- SLASH = "/".freeze
174
155
  REQUEST_METHOD = "REQUEST_METHOD".freeze
175
- GET = "GET".freeze
176
156
  HEAD = "HEAD".freeze
177
157
  # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
178
- ETAG_FORMAT = "\"%x-%x-%x\"".freeze
179
158
  LINE_END = "\r\n".freeze
180
159
  REMOTE_ADDR = "REMOTE_ADDR".freeze
181
160
  HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR".freeze
182
- HTTP_IF_MODIFIED_SINCE = "HTTP_IF_MODIFIED_SINCE".freeze
183
- HTTP_IF_NONE_MATCH = "HTTP_IF_NONE_MATCH".freeze
184
- REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
185
- HOST = "HOST".freeze
186
161
 
187
162
  SERVER_NAME = "SERVER_NAME".freeze
188
163
  SERVER_PORT = "SERVER_PORT".freeze
@@ -195,7 +170,6 @@ module Puma
195
170
 
196
171
  SERVER_PROTOCOL = "SERVER_PROTOCOL".freeze
197
172
  HTTP_11 = "HTTP/1.1".freeze
198
- HTTP_10 = "HTTP/1.0".freeze
199
173
 
200
174
  SERVER_SOFTWARE = "SERVER_SOFTWARE".freeze
201
175
  GATEWAY_INTERFACE = "GATEWAY_INTERFACE".freeze
@@ -219,7 +193,10 @@ module Puma
219
193
 
220
194
  HTTP_VERSION = "HTTP_VERSION".freeze
221
195
  HTTP_CONNECTION = "HTTP_CONNECTION".freeze
196
+ HTTP_EXPECT = "HTTP_EXPECT".freeze
197
+ CONTINUE = "100-continue".freeze
222
198
 
199
+ HTTP_11_100 = "HTTP/1.1 100 Continue\r\n\r\n".freeze
223
200
  HTTP_11_200 = "HTTP/1.1 200 OK\r\n".freeze
224
201
  HTTP_10_200 = "HTTP/1.0 200 OK\r\n".freeze
225
202
 
@@ -229,6 +206,7 @@ module Puma
229
206
  CONTENT_LENGTH2 = "content-length".freeze
230
207
  CONTENT_LENGTH_S = "Content-Length: ".freeze
231
208
  TRANSFER_ENCODING = "transfer-encoding".freeze
209
+ TRANSFER_ENCODING2 = "HTTP_TRANSFER_ENCODING".freeze
232
210
 
233
211
  CONNECTION_CLOSE = "Connection: close\r\n".freeze
234
212
  CONNECTION_KEEP_ALIVE = "Connection: Keep-Alive\r\n".freeze
@@ -236,6 +214,8 @@ module Puma
236
214
  TRANSFER_ENCODING_CHUNKED = "Transfer-Encoding: chunked\r\n".freeze
237
215
  CLOSE_CHUNKED = "0\r\n\r\n".freeze
238
216
 
217
+ CHUNKED = "chunked".freeze
218
+
239
219
  COLON = ": ".freeze
240
220
 
241
221
  NEWLINE = "\n".freeze
@@ -243,5 +223,7 @@ module Puma
243
223
  HIJACK_P = "rack.hijack?".freeze
244
224
  HIJACK = "rack.hijack".freeze
245
225
  HIJACK_IO = "rack.hijack_io".freeze
226
+
227
+ EARLY_HINTS = "rack.early_hints".freeze
246
228
  end
247
229
  end
@@ -1,5 +1,5 @@
1
1
  require 'optparse'
2
- require 'puma'
2
+ require 'puma/state_file'
3
3
  require 'puma/const'
4
4
  require 'puma/detect'
5
5
  require 'puma/configuration'
@@ -9,7 +9,7 @@ require 'socket'
9
9
  module Puma
10
10
  class ControlCLI
11
11
 
12
- COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
12
+ COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
13
13
 
14
14
  def initialize(argv, stdout=STDOUT, stderr=STDERR)
15
15
  @state = nil
@@ -69,6 +69,7 @@ module Puma
69
69
  end
70
70
 
71
71
  opts.order!(argv) { |a| opts.terminate a }
72
+ opts.parse!
72
73
 
73
74
  @command = argv.shift
74
75
 
@@ -78,11 +79,12 @@ module Puma
78
79
  end
79
80
 
80
81
  if @config_file
81
- config = Puma::Configuration.from_file @config_file
82
- @state ||= config.options[:state]
83
- @control_url ||= config.options[:control_url]
82
+ config = Puma::Configuration.new({ config_files: [@config_file] }, {})
83
+ config.load
84
+ @state ||= config.options[:state]
85
+ @control_url ||= config.options[:control_url]
84
86
  @control_auth_token ||= config.options[:control_auth_token]
85
- @pidfile ||= config.options[:pidfile]
87
+ @pidfile ||= config.options[:pidfile]
86
88
  end
87
89
  end
88
90
 
@@ -97,6 +99,7 @@ module Puma
97
99
 
98
100
  rescue => e
99
101
  @stdout.puts e.message
102
+ @stdout.puts e.backtrace
100
103
  exit 1
101
104
  end
102
105
 
@@ -167,7 +170,7 @@ module Puma
167
170
  end
168
171
 
169
172
  message "Command #{@command} sent success"
170
- message response.last if @command == "stats"
173
+ message response.last if @command == "stats" || @command == "gc-stats"
171
174
  end
172
175
 
173
176
  @server.close
@@ -179,46 +182,45 @@ module Puma
179
182
  end
180
183
 
181
184
  begin
182
- Process.getpgid @pid
183
- rescue SystemCallError
184
- if @command == "restart"
185
- start
186
- else
187
- raise "No pid '#{@pid}' found"
188
- end
189
- end
190
185
 
191
- case @command
192
- when "restart"
193
- Process.kill "SIGUSR2", @pid
186
+ case @command
187
+ when "restart"
188
+ Process.kill "SIGUSR2", @pid
194
189
 
195
- when "halt"
196
- Process.kill "QUIT", @pid
190
+ when "halt"
191
+ Process.kill "QUIT", @pid
197
192
 
198
- when "stop"
199
- Process.kill "SIGTERM", @pid
193
+ when "stop"
194
+ Process.kill "SIGTERM", @pid
200
195
 
201
- when "stats"
202
- puts "Stats not available via pid only"
203
- return
196
+ when "stats"
197
+ puts "Stats not available via pid only"
198
+ return
204
199
 
205
- when "reload-worker-directory"
206
- puts "reload-worker-directory not available via pid only"
207
- return
200
+ when "reload-worker-directory"
201
+ puts "reload-worker-directory not available via pid only"
202
+ return
208
203
 
209
- when "phased-restart"
210
- Process.kill "SIGUSR1", @pid
204
+ when "phased-restart"
205
+ Process.kill "SIGUSR1", @pid
211
206
 
212
- else
213
- message "Puma is started"
214
- return
207
+ else
208
+ return
209
+ end
210
+
211
+ rescue SystemCallError
212
+ if @command == "restart"
213
+ start
214
+ else
215
+ raise "No pid '#{@pid}' found"
216
+ end
215
217
  end
216
218
 
217
219
  message "Command #{@command} sent success"
218
220
  end
219
221
 
220
222
  def run
221
- start if @command == "start"
223
+ return start if @command == "start"
222
224
 
223
225
  prepare_configuration
224
226
 
@@ -230,6 +232,7 @@ module Puma
230
232
 
231
233
  rescue => e
232
234
  message e.message
235
+ message e.backtrace
233
236
  exit 1
234
237
  end
235
238
 
@@ -242,7 +245,7 @@ module Puma
242
245
  run_args += ["-S", @state] if @state
243
246
  run_args += ["-q"] if @quiet
244
247
  run_args += ["--pidfile", @pidfile] if @pidfile
245
- run_args += ["--control", @control_url] if @control_url
248
+ run_args += ["--control-url", @control_url] if @control_url
246
249
  run_args += ["--control-token", @control_auth_token] if @control_auth_token
247
250
  run_args += ["-C", @config_file] if @config_file
248
251
 
@@ -3,12 +3,12 @@ require 'puma/configuration'
3
3
 
4
4
  module Puma
5
5
  def self.run(opts={})
6
- cfg = Puma::Configuration.new do |c|
6
+ cfg = Puma::Configuration.new do |user_config|
7
7
  if port = opts[:port]
8
- c.port port
8
+ user_config.port port
9
9
  end
10
10
 
11
- c.quiet
11
+ user_config.quiet
12
12
 
13
13
  yield c
14
14
  end
@@ -5,7 +5,9 @@ module Puma
5
5
  IS_JRUBY
6
6
  end
7
7
 
8
+ IS_WINDOWS = RUBY_PLATFORM =~ /mswin|ming|cygwin/
9
+
8
10
  def self.windows?
9
- RUBY_PLATFORM =~ /mswin32|ming32/
11
+ IS_WINDOWS
10
12
  end
11
13
  end
@@ -1,20 +1,35 @@
1
1
  module Puma
2
2
  # The methods that are available for use inside the config file.
3
+ # These same methods are used in Puma cli and the rack handler
4
+ # internally.
3
5
  #
6
+ # Used manually (via CLI class):
7
+ #
8
+ # config = Configuration.new({}) do |user_config|
9
+ # user_config.port 3001
10
+ # end
11
+ # config.load
12
+ #
13
+ # puts config.options[:binds]
14
+ # "tcp://127.0.0.1:3001"
15
+ #
16
+ # Used to load file:
17
+ #
18
+ # $ cat puma_config.rb
19
+ # port 3002
20
+ #
21
+ # config = Configuration.new(config_file: "puma_config.rb")
22
+ # config.load
23
+ #
24
+ # puts config.options[:binds]
25
+ # # => "tcp://127.0.0.1:3002"
26
+ #
27
+ # Detailed docs can be found in `examples/config.rb`
4
28
  class DSL
5
29
  include ConfigDefault
6
30
 
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
31
  def initialize(options, config)
17
- @config = config
32
+ @config = config
18
33
  @options = options
19
34
 
20
35
  @plugins = []
@@ -40,36 +55,10 @@ module Puma
40
55
  @plugins.clear
41
56
  end
42
57
 
43
- def _run(&blk)
44
- blk.call self
45
- ensure
46
- _offer_plugins
47
- end
48
-
49
58
  def inject(&blk)
50
59
  instance_eval(&blk)
51
60
  end
52
61
 
53
- # Load configuration from another named file. If the file name is absolute,
54
- # load the file as an absolute path. Otherwise load it relative to the
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
- end
72
-
73
62
  def get(key,default=nil)
74
63
  @options[key.to_sym] || default
75
64
  end
@@ -115,15 +104,35 @@ module Puma
115
104
  end
116
105
 
117
106
  # Load additional configuration from a file
107
+ # Files get loaded later via Configuration#load
118
108
  def load(file)
119
- _ary(:config_files) << file
109
+ @options[:config_files] ||= []
110
+ @options[:config_files] << file
120
111
  end
121
112
 
122
- # Bind the server to +url+. tcp:// and unix:// are the only accepted
123
- # protocols.
113
+ # Adds a binding for the server to +url+. tcp://, unix://, and ssl:// are the only accepted
114
+ # protocols. Use query parameters within the url to specify options.
115
+ #
116
+ # @note multiple urls can be bound to, calling `bind` does not overwrite previous bindings.
117
+ #
118
+ # @example Explicitly the socket backlog depth (default is 1024)
119
+ # bind('unix:///var/run/puma.sock?backlog=2048')
124
120
  #
121
+ # @example Set up ssl cert
122
+ # bind('ssl://127.0.0.1:9292?key=key.key&cert=cert.pem')
123
+ #
124
+ # @example Prefer low-latency over higher throughput (via `Socket::TCP_NODELAY`)
125
+ # bind('tcp://0.0.0.0:9292?low_latency=true')
126
+ #
127
+ # @example Set socket permissions
128
+ # bind('unix:///var/run/puma.sock?umask=0111')
125
129
  def bind(url)
126
- _ary(:binds) << url
130
+ @options[:binds] ||= []
131
+ @options[:binds] << url
132
+ end
133
+
134
+ def clear_binds!
135
+ @options[:binds] = []
127
136
  end
128
137
 
129
138
  # Define the TCP port to bind to. Use +bind+ for more advanced options.
@@ -133,6 +142,19 @@ module Puma
133
142
  bind "tcp://#{host}:#{port}"
134
143
  end
135
144
 
145
+ # Define how long persistent connections can be idle before puma closes
146
+ # them
147
+ #
148
+ def persistent_timeout(seconds)
149
+ @options[:persistent_timeout] = Integer(seconds)
150
+ end
151
+
152
+ # Define how long the tcp socket stays open, if no data has been received
153
+ #
154
+ def first_data_timeout(seconds)
155
+ @options[:first_data_timeout] = Integer(seconds)
156
+ end
157
+
136
158
  # Work around leaky apps that leave garbage in Thread locals
137
159
  # across requests
138
160
  #
@@ -147,7 +169,7 @@ module Puma
147
169
  end
148
170
 
149
171
  # When shutting down, drain the accept socket of pending
150
- # connections and proces them. This loops over the accept
172
+ # connections and process them. This loops over the accept
151
173
  # socket until there are no more read events and then stops
152
174
  # looking and waits for the requests to finish.
153
175
  def drain_on_shutdown(which=true)
@@ -185,7 +207,8 @@ module Puma
185
207
  # This can be called multiple times to add code each time.
186
208
  #
187
209
  def on_restart(&block)
188
- _ary(:on_restart) << block
210
+ @options[:on_restart] ||= []
211
+ @options[:on_restart] << block
189
212
  end
190
213
 
191
214
  # Command to use to restart puma. This should be just how to
@@ -231,6 +254,10 @@ module Puma
231
254
  @options[:mode] = :tcp
232
255
  end
233
256
 
257
+ def early_hints(answer=true)
258
+ @options[:early_hints] = answer
259
+ end
260
+
234
261
  # Redirect STDOUT and STDERR to files specified.
235
262
  def stdout_redirect(stdout=nil, stderr=nil, append=false)
236
263
  @options[:redirect_stdout] = stdout
@@ -257,11 +284,13 @@ module Puma
257
284
  end
258
285
 
259
286
  def ssl_bind(host, port, opts)
287
+ verify = opts.fetch(:verify_mode, 'none')
288
+
260
289
  if defined?(JRUBY_VERSION)
261
290
  keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
262
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
291
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}"
263
292
  else
264
- bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
293
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&verify_mode=#{verify}"
265
294
  end
266
295
  end
267
296
 
@@ -288,7 +317,8 @@ module Puma
288
317
  # This can be called multiple times to add hooks.
289
318
  #
290
319
  def before_fork(&block)
291
- _ary(:before_fork) << block
320
+ @options[:before_fork] ||= []
321
+ @options[:before_fork] << block
292
322
  end
293
323
 
294
324
  # *Cluster mode only* Code to run in a worker when it boots to setup
@@ -297,7 +327,8 @@ module Puma
297
327
  # This can be called multiple times to add hooks.
298
328
  #
299
329
  def on_worker_boot(&block)
300
- _ary(:before_worker_boot) << block
330
+ @options[:before_worker_boot] ||= []
331
+ @options[:before_worker_boot] << block
301
332
  end
302
333
 
303
334
  # *Cluster mode only* Code to run immediately before a worker shuts
@@ -308,7 +339,8 @@ module Puma
308
339
  # This can be called multiple times to add hooks.
309
340
  #
310
341
  def on_worker_shutdown(&block)
311
- _ary(:before_worker_shutdown) << block
342
+ @options[:before_worker_shutdown] ||= []
343
+ @options[:before_worker_shutdown] << block
312
344
  end
313
345
 
314
346
  # *Cluster mode only* Code to run in the master when it is
@@ -317,7 +349,8 @@ module Puma
317
349
  # This can be called multiple times to add hooks.
318
350
  #
319
351
  def on_worker_fork(&block)
320
- _ary(:before_worker_fork) << block
352
+ @options[:before_worker_fork] ||= []
353
+ @options[:before_worker_fork] << block
321
354
  end
322
355
 
323
356
  # *Cluster mode only* Code to run in the master after it starts
@@ -326,7 +359,8 @@ module Puma
326
359
  # This can be called multiple times to add hooks.
327
360
  #
328
361
  def after_worker_fork(&block)
329
- _ary(:after_worker_fork) << block
362
+ @options[:after_worker_fork] ||= []
363
+ @options[:after_worker_fork] = block
330
364
  end
331
365
 
332
366
  alias_method :after_worker_boot, :after_worker_fork
@@ -390,17 +424,17 @@ module Puma
390
424
  # that have not checked in within the given +timeout+.
391
425
  # This mitigates hung processes. Default value is 60 seconds.
392
426
  def worker_timeout(timeout)
393
- @options[:worker_timeout] = timeout
427
+ @options[:worker_timeout] = Integer(timeout)
394
428
  end
395
429
 
396
430
  # *Cluster mode only* Set the timeout for workers to boot
397
431
  def worker_boot_timeout(timeout)
398
- @options[:worker_boot_timeout] = timeout
432
+ @options[:worker_boot_timeout] = Integer(timeout)
399
433
  end
400
434
 
401
435
  # *Cluster mode only* Set the timeout for worker shutdown
402
436
  def worker_shutdown_timeout(timeout)
403
- @options[:worker_shutdown_timeout] = timeout
437
+ @options[:worker_shutdown_timeout] = Integer(timeout)
404
438
  end
405
439
 
406
440
  # When set to true (the default), workers accept all requests
@@ -468,10 +502,5 @@ module Puma
468
502
  end
469
503
  end
470
504
 
471
- private
472
-
473
- def _ary(key)
474
- (@options.cur[key] ||= [])
475
- end
476
505
  end
477
506
  end