puma 3.3.0 → 3.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7069953b7e057c1aa73536b3aefccae709151c92
4
- data.tar.gz: 50635cce883fd9a576b9db23a29c7a6a2d3a3526
3
+ metadata.gz: 59d465d75e9f9cbc7ebb6ae7f26dfc531e995b2e
4
+ data.tar.gz: 93ba7123b7902f390ada3d933b645b969db2afb0
5
5
  SHA512:
6
- metadata.gz: 347ecd7db9802483c8c8caf9dfd75acad3bd5d86b32fb47371a377764d685d9bfe2a36ae060643935b19007f5ba93b4cfbe0d531c3536de65dd7d2bfa72973ed
7
- data.tar.gz: 8d33efdeeb7b842d79c4cb35228757910bdebca22928d282fb97c56d128ff5567bf7caefda0692ceca0e1669096918aa5993c11efc3e4caae7fd73654bb06101
6
+ metadata.gz: ade21758b2cf93fefcfd443b0b19dcbd752ab4d3eff57ccfd86c3e08edb4330157a4f6259736007f73bc1770dc2a4ddc3c1ac696109f1ec944a30bdb6852d05c
7
+ data.tar.gz: 3143e6dc4f02b4e2a0afbfe32434040211d0eb07623adceeb37c3d4774ded1a50863e31030606e3dd7d351fece77d948ee2f0ccdbab132cd426f133f94777d1f
@@ -1,3 +1,26 @@
1
+ === 3.4.0 / 2016-04-07
2
+
3
+ * 2 minor features:
4
+ * Add ability to force threads to stop on shutdown. Fixes #938
5
+ * Detect and commit seppuku when fork(2) fails. Fixes #529
6
+
7
+ * 3 unknowns:
8
+ * Ignore errors trying to update the backport tables. Fixes #788
9
+ * Invoke the lowlevel_error in more places to allow for exception tracking. Fixes #894
10
+ * Update the query string when an absolute URI is used. Fixes #937
11
+
12
+ * 5 doc fixes:
13
+ * Add Process Monitors section to top-level README
14
+ * Better document the hooks. Fixes #840
15
+ * docs/system.md sample config refinements and elaborations
16
+ * Fix typos at couple of places.
17
+ * Cleanup warnings
18
+
19
+ * 3 PRs merged:
20
+ * Merge pull request #945 from dekellum/systemd-docs-refined
21
+ * Merge pull request #946 from vipulnsward/rm-pid
22
+ * Merge pull request #947 from vipulnsward/housekeeping-typos
23
+
1
24
  === 3.3.0 / 2016-04-05
2
25
 
3
26
  * 2 minor features:
@@ -980,7 +1003,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
980
1003
 
981
1004
  === 1.5.0 / 2012-07-19
982
1005
 
983
- * 7 contributers to this release:
1006
+ * 7 contributors to this release:
984
1007
  * Christian Mayer
985
1008
  * Darío Javier Cravero
986
1009
  * Dirkjan Bussink
@@ -1028,7 +1051,7 @@ be added back in a future date when a java Puma::MiniSSL is added.
1028
1051
  * Only stop the status server if it's started. Fixes #84
1029
1052
  * Set RACK_ENV early in cli also. Fixes #78
1030
1053
 
1031
- * 1 new contributer:
1054
+ * 1 new contributor:
1032
1055
  * Jesse Cooke
1033
1056
 
1034
1057
  === 1.2.2 / 2012-04-28
@@ -1064,9 +1087,9 @@ be added back in a future date when a java Puma::MiniSSL is added.
1064
1087
  * Fix reporting https only on a true SSL connection
1065
1088
  * Set the default content type to 'text/plain'. Fixes #63
1066
1089
  * Use REUSEADDR. Fixes #60
1067
- * Shutdown gracefull on SIGTERM. Fixes #53
1090
+ * Shutdown gracefully on SIGTERM. Fixes #53
1068
1091
 
1069
- 2 new contributers:
1092
+ 2 new contributors:
1070
1093
 
1071
1094
  * Seamus Abshere
1072
1095
  * Steve Richert
data/README.md CHANGED
@@ -238,7 +238,7 @@ To perform a restart, there are 2 builtin mechanisms:
238
238
 
239
239
  No code is shared between the current and restarted process, so it should be safe to issue a restart any place where you would manually stop Puma and start it again.
240
240
 
241
- If the new process is unable to load, it will simply exit. You should therefore run Puma under a supervisor when using it in production.
241
+ If the new process is unable to load, it will simply exit. You should therefore run Puma under a process monitor (see below) when using it in production.
242
242
 
243
243
  ### Normal vs Hot vs Phased Restart
244
244
 
@@ -295,9 +295,15 @@ Because of various platforms not being able to implement certain things, the fol
295
295
 
296
296
  `pumactl` is a simple CLI frontend to the control/status app described above. Please refer to `pumactl --help` for available commands.
297
297
 
298
- ## Managing multiple Pumas / init.d / upstart scripts
298
+ ## Process Monitors
299
299
 
300
- If you want an easy way to manage multiple scripts at once, check [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for init.d and upstart scripts.
300
+ Process monitors or supervisors will at minimum provide start of Puma
301
+ on system boot. Modern process monitors like systemd or upstart
302
+ further provide continuous monitoring and restarts for increased
303
+ reliability in production environments:
304
+
305
+ * [tools/jungle](https://github.com/puma/puma/tree/master/tools/jungle) for sysvinit (init.d) and upstart
306
+ * [docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md)
301
307
 
302
308
  ## Capistrano deployment
303
309
 
@@ -34,7 +34,7 @@ server {
34
34
  proxy_set_header Host $http_host;
35
35
 
36
36
  # If the file exists as a static file serve it directly without
37
- # running all the other rewite tests on it
37
+ # running all the other rewrite tests on it
38
38
  if (-f $request_filename) {
39
39
  break;
40
40
  }
@@ -50,7 +50,7 @@ server {
50
50
  # this is the meat of the rack page caching config
51
51
  # it adds .html to the end of the url and then checks
52
52
  # the filesystem for that file. If it exists, then we
53
- # rewite the url to have explicit .html on the end
53
+ # rewrite the url to have explicit .html on the end
54
54
  # and then send it on its way to the next config rule.
55
55
  # if there is no file on the fs then it sets all the
56
56
  # necessary headers and proxies to our upstream pumas
@@ -11,6 +11,9 @@ puma.service configuration file for systemd:
11
11
  Description=Puma HTTP Server
12
12
  After=network.target
13
13
 
14
+ # Uncomment for socket activation (see below)
15
+ # Requires=puma.socket
16
+
14
17
  [Service]
15
18
  # Foreground process (do not use --daemon in ExecStart or config.rb)
16
19
  Type=simple
@@ -33,7 +36,7 @@ Type=simple
33
36
 
34
37
  # Alternatively with a config file (in WorkingDirectory) and
35
38
  # comparable `bind` directives
36
- # ExecStart=<WorkingDirectory>/sbin/puma -C config.rb
39
+ # ExecStart=<WD>/sbin/puma -C config.rb
37
40
 
38
41
  Restart=always
39
42
 
@@ -66,13 +69,102 @@ ListenStream=0.0.0.0:9293
66
69
  # SocketUser, SocketGroup, etc. may be needed for Unix domain sockets
67
70
  # ListenStream=/run/puma.sock
68
71
 
69
- # Socket options matching what Puma wants
72
+ # Socket options matching Puma defaults
70
73
  NoDelay=true
71
74
  ReusePort=true
75
+ Backlog=1024
72
76
 
73
77
  [Install]
74
78
  WantedBy=sockets.target
75
79
  ~~~~
76
80
 
77
81
  See [systemd.socket](https://www.freedesktop.org/software/systemd/man/systemd.socket.html)
78
- for additional details.
82
+ for additional configuration details.
83
+
84
+ Note that the above configurations will work with Puma in either
85
+ single process or cluster mode.
86
+
87
+ ## Usage
88
+
89
+ Without socket activation, use `systemctl` as root (e.g. via `sudo`) as
90
+ with other system services:
91
+
92
+ ~~~~ sh
93
+ # After installing or making changes to puma.service
94
+ systemctl daemon-reload
95
+
96
+ # Enable so it starts on boot
97
+ systemctl enable puma.service
98
+
99
+ # Initial start up.
100
+ systemctl start puma.service
101
+
102
+ # Check status
103
+ systemctl status puma.service
104
+
105
+ # A normal restart. Warning: listeners sockets will be closed
106
+ # while a new puma process initializes.
107
+ systemctl restart puma.service
108
+ ~~~~
109
+
110
+ With socket activation, several but not all of these commands should
111
+ be run for both socket and service:
112
+
113
+ ~~~~ sh
114
+ # After installing or making changes to either puma.socket or
115
+ # puma.service.
116
+ systemctl daemon-reload
117
+
118
+ # Enable both socket and service so they start on boot. Alternatively
119
+ # you could leave puma.service disabled and systemd will start it on
120
+ # first use (with startup lag on first request)
121
+ systemctl enable puma.socket puma.service
122
+
123
+ # Initial start up. The Requires directive (see above) ensures the
124
+ # socket is started before the service.
125
+ systemctl start puma.socket puma.service
126
+
127
+ # Check status of both socket and service.
128
+ systemctl status puma.socket puma.service
129
+
130
+ # A "hot" restart, with systemd keeping puma.socket listening and
131
+ # providing to the new puma (master) instance.
132
+ systemctl restart puma.service
133
+
134
+ # A normal restart, needed to handle changes to
135
+ # puma.socket, such as changing the ListenStream ports. Note
136
+ # daemon-reload (above) should be run first.
137
+ systemctl restart puma.socket puma.service
138
+ ~~~~
139
+
140
+ Here is sample output from `systemctl status` with both service and
141
+ socket running:
142
+
143
+ ~~~~
144
+ ● puma.socket - Puma HTTP Server Accept Sockets
145
+ Loaded: loaded (/etc/systemd/system/puma.socket; enabled; vendor preset: enabled)
146
+ Active: active (running) since Thu 2016-04-07 08:40:19 PDT; 1h 2min ago
147
+ Listen: 0.0.0.0:9233 (Stream)
148
+ 0.0.0.0:9234 (Stream)
149
+
150
+ Apr 07 08:40:19 hx systemd[874]: Listening on Puma HTTP Server Accept Sockets.
151
+
152
+ ● puma.service - Puma HTTP Server
153
+ Loaded: loaded (/etc/systemd/system/puma.service; enabled; vendor preset: enabled)
154
+ Active: active (running) since Thu 2016-04-07 08:40:19 PDT; 1h 2min ago
155
+ Main PID: 28320 (ruby)
156
+ CGroup: /system.slice/puma.service
157
+ ├─28320 puma 3.3.0 (tcp://0.0.0.0:9233,ssl://0.0.0.0:9234?key=key.pem&cert=cert.pem) [app]
158
+ ├─28323 puma: cluster worker 0: 28320 [app]
159
+ └─28327 puma: cluster worker 1: 28320 [app]
160
+
161
+ Apr 07 08:40:19 hx puma[28320]: Puma starting in cluster mode...
162
+ Apr 07 08:40:19 hx puma[28320]: * Version 3.3.0 (ruby 2.2.4-p230), codename: Jovial Platypus
163
+ Apr 07 08:40:19 hx puma[28320]: * Min threads: 0, max threads: 16
164
+ Apr 07 08:40:19 hx puma[28320]: * Environment: production
165
+ Apr 07 08:40:19 hx puma[28320]: * Process workers: 2
166
+ Apr 07 08:40:19 hx puma[28320]: * Phased restart available
167
+ Apr 07 08:40:19 hx puma[28320]: * Activated tcp://0.0.0.0:9233
168
+ Apr 07 08:40:19 hx puma[28320]: * Activated ssl://0.0.0.0:9234?key=key.pem&cert=cert.pem
169
+ Apr 07 08:40:19 hx puma[28320]: Use Ctrl-C to stop
170
+ ~~~~
@@ -23,7 +23,7 @@ module Puma
23
23
  "SCRIPT_NAME".freeze => ENV['SCRIPT_NAME'] || "",
24
24
 
25
25
  # I'd like to set a default CONTENT_TYPE here but some things
26
- # depend on their not being a default set and infering
26
+ # depend on their not being a default set and inferring
27
27
  # it from the content. And so if i set it here, it won't
28
28
  # infer properly.
29
29
 
@@ -230,7 +230,7 @@ module Puma
230
230
  end
231
231
  end
232
232
 
233
- # Also close any unsued activated sockets
233
+ # Also close any unused activated sockets
234
234
  @activated_sockets.each do |key, sock|
235
235
  logger.log "* Closing unused activated socket: #{key.join ':'}"
236
236
  begin
@@ -118,6 +118,12 @@ module Puma
118
118
  @launcher.config.run_hooks :before_worker_fork, idx
119
119
 
120
120
  pid = fork { worker(idx, master) }
121
+ if !pid
122
+ log "! Complete inability to spawn new workers detected"
123
+ log "! Seppuku is the only choice."
124
+ exit! 1
125
+ end
126
+
121
127
  debug "Spawned worker: #{pid}"
122
128
  @workers << Worker.new(idx, pid, @phase, @options)
123
129
 
@@ -100,8 +100,8 @@ module Puma
100
100
  # too taxing on performance.
101
101
  module Const
102
102
 
103
- PUMA_VERSION = VERSION = "3.3.0".freeze
104
- CODE_NAME = "Jovial Platypus".freeze
103
+ PUMA_VERSION = VERSION = "3.4.0".freeze
104
+ CODE_NAME = "Owl Bowl Brawl".freeze
105
105
  PUMA_SERVER_STRING = ['puma', PUMA_VERSION, CODE_NAME].join(' ').freeze
106
106
 
107
107
  FAST_TRACK_KA_TIMEOUT = 0.2
@@ -118,6 +118,11 @@ module Puma
118
118
  # sending data back
119
119
  WRITE_TIMEOUT = 10
120
120
 
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
+
121
126
  DATE = "Date".freeze
122
127
 
123
128
  SCRIPT_NAME = "SCRIPT_NAME".freeze
@@ -125,6 +130,7 @@ module Puma
125
130
  # The original URI requested by the client.
126
131
  REQUEST_URI= 'REQUEST_URI'.freeze
127
132
  REQUEST_PATH = 'REQUEST_PATH'.freeze
133
+ QUERY_STRING = 'QUERY_STRING'.freeze
128
134
 
129
135
  PATH_INFO = 'PATH_INFO'.freeze
130
136
 
@@ -159,6 +159,26 @@ module Puma
159
159
  @options[:environment] = environment
160
160
  end
161
161
 
162
+ # How long to wait for threads to stop when shutting them
163
+ # down. Defaults to :forever. Specifying :immediately will cause
164
+ # Puma to kill the threads immediately. Otherwise the value
165
+ # is the number of seconds to wait.
166
+ #
167
+ # Puma always waits a few seconds after killing a thread for it to try
168
+ # to finish up it's work, even in :immediately mode.
169
+ def force_shutdown_after(val=:forever)
170
+ i = case val
171
+ when :forever
172
+ -1
173
+ when :immediately
174
+ 0
175
+ else
176
+ Integer(val)
177
+ end
178
+
179
+ @options[:force_shutdown_after] = i
180
+ end
181
+
162
182
  # Code to run before doing a restart. This code should
163
183
  # close logfiles, database connections, etc.
164
184
  #
@@ -271,6 +291,15 @@ module Puma
271
291
  _ary(:before_fork) << block
272
292
  end
273
293
 
294
+ # *Cluster mode only* Code to run in a worker when it boots to setup
295
+ # the process before booting the app.
296
+ #
297
+ # This can be called multiple times to add hooks.
298
+ #
299
+ def on_worker_boot(&block)
300
+ _ary(:before_worker_boot) << block
301
+ end
302
+
274
303
  # *Cluster mode only* Code to run immediately before a worker shuts
275
304
  # down (after it has finished processing HTTP requests). These hooks
276
305
  # can block if necessary to wait for background operations unknown
@@ -282,16 +311,7 @@ module Puma
282
311
  _ary(:before_worker_shutdown) << block
283
312
  end
284
313
 
285
- # *Cluster mode only* Code to run when a worker boots to setup
286
- # the process before booting the app.
287
- #
288
- # This can be called multiple times to add hooks.
289
- #
290
- def on_worker_boot(&block)
291
- _ary(:before_worker_boot) << block
292
- end
293
-
294
- # *Cluster mode only* Code to run when a master process is
314
+ # *Cluster mode only* Code to run in the master when it is
295
315
  # about to create the worker by forking itself.
296
316
  #
297
317
  # This can be called multiple times to add hooks.
@@ -300,15 +320,17 @@ module Puma
300
320
  _ary(:before_worker_fork) << block
301
321
  end
302
322
 
303
- # *Cluster mode only* Code to run when a worker boots to setup
304
- # the process after booting the app.
323
+ # *Cluster mode only* Code to run in the master after it starts
324
+ # a worker.
305
325
  #
306
326
  # This can be called multiple times to add hooks.
307
327
  #
308
- def after_worker_boot(&block)
328
+ def after_worker_fork(&block)
309
329
  _ary(:after_worker_fork) << block
310
330
  end
311
331
 
332
+ alias_method :after_worker_boot, :after_worker_fork
333
+
312
334
  # The directory to operate out of.
313
335
  def directory(dir)
314
336
  @options[:directory] = dir.to_s
@@ -12,7 +12,7 @@ require 'puma/state_file'
12
12
  require 'puma/commonlogger'
13
13
 
14
14
  module Puma
15
- # Puam::Launcher is the single entry point for starting a Puma server based on user
15
+ # Puma::Launcher is the single entry point for starting a Puma server based on user
16
16
  # configuration. It is responsible for taking user supplied arguments and resolving them
17
17
  # with configuration in `config/puma.rb` or `config/puma/<env>.rb`.
18
18
  #
@@ -7,22 +7,25 @@
7
7
  #
8
8
 
9
9
  module URI
10
- TBLENCWWWCOMP_ = {} # :nodoc:
11
- 256.times do |i|
12
- TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
13
- end
14
- TBLENCWWWCOMP_[' '] = '+'
15
- TBLENCWWWCOMP_.freeze
16
- TBLDECWWWCOMP_ = {} # :nodoc:
17
- 256.times do |i|
18
- h, l = i>>4, i&15
19
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
20
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
21
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
22
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
10
+ begin
11
+ TBLENCWWWCOMP_ = {} # :nodoc:
12
+ 256.times do |i|
13
+ TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
14
+ end
15
+ TBLENCWWWCOMP_[' '] = '+'
16
+ TBLENCWWWCOMP_.freeze
17
+ TBLDECWWWCOMP_ = {} # :nodoc:
18
+ 256.times do |i|
19
+ h, l = i>>4, i&15
20
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
21
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
22
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
23
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
24
+ end
25
+ TBLDECWWWCOMP_['+'] = ' '
26
+ TBLDECWWWCOMP_.freeze
27
+ rescue Exception
23
28
  end
24
- TBLDECWWWCOMP_['+'] = ' '
25
- TBLDECWWWCOMP_.freeze
26
29
 
27
30
  # Encode given +s+ to URL-encoded form data.
28
31
  #
@@ -17,17 +17,20 @@
17
17
  require 'uri/common'
18
18
 
19
19
  module URI
20
- TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
21
- if TBLDECWWWCOMP_.empty?
22
- 256.times do |i|
23
- h, l = i>>4, i&15
24
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
25
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
26
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
27
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
20
+ begin
21
+ TBLDECWWWCOMP_ = {} unless const_defined?(:TBLDECWWWCOMP_) #:nodoc:
22
+ if TBLDECWWWCOMP_.empty?
23
+ 256.times do |i|
24
+ h, l = i>>4, i&15
25
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
26
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
27
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
28
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
29
+ end
30
+ TBLDECWWWCOMP_['+'] = ' '
31
+ TBLDECWWWCOMP_.freeze
28
32
  end
29
- TBLDECWWWCOMP_['+'] = ' '
30
- TBLDECWWWCOMP_.freeze
33
+ rescue Exception
31
34
  end
32
35
 
33
36
  def self.decode_www_form(str, enc=Encoding::UTF_8)
@@ -8,22 +8,26 @@ require 'uri/common'
8
8
  # Relevant commit:
9
9
  # https://github.com/ruby/ruby/commit/edb7cdf1eabaff78dfa5ffedfbc2e91b29fa9ca1
10
10
 
11
+
11
12
  module URI
12
- 256.times do |i|
13
- TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
14
- end
15
- TBLENCWWWCOMP_[' '] = '+'
16
- TBLENCWWWCOMP_.freeze
13
+ begin
14
+ 256.times do |i|
15
+ TBLENCWWWCOMP_[i.chr] = '%%%02X' % i
16
+ end
17
+ TBLENCWWWCOMP_[' '] = '+'
18
+ TBLENCWWWCOMP_.freeze
17
19
 
18
- 256.times do |i|
19
- h, l = i>>4, i&15
20
- TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
21
- TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
22
- TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
23
- TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
20
+ 256.times do |i|
21
+ h, l = i>>4, i&15
22
+ TBLDECWWWCOMP_['%%%X%X' % [h, l]] = i.chr
23
+ TBLDECWWWCOMP_['%%%x%X' % [h, l]] = i.chr
24
+ TBLDECWWWCOMP_['%%%X%x' % [h, l]] = i.chr
25
+ TBLDECWWWCOMP_['%%%x%x' % [h, l]] = i.chr
26
+ end
27
+ TBLDECWWWCOMP_['+'] = ' '
28
+ TBLDECWWWCOMP_.freeze
29
+ rescue Exception
24
30
  end
25
- TBLDECWWWCOMP_['+'] = ' '
26
- TBLDECWWWCOMP_.freeze
27
31
  end
28
32
 
29
33
  # :startdoc:
@@ -77,6 +77,8 @@ module Puma
77
77
 
78
78
  # SSL handshake failure
79
79
  rescue MiniSSL::SSLError => e
80
+ @server.lowlevel_error(e, c.env)
81
+
80
82
  ssl_socket = c.io
81
83
  addr = ssl_socket.peeraddr.last
82
84
  cert = ssl_socket.peercert
@@ -88,6 +90,8 @@ module Puma
88
90
 
89
91
  # The client doesn't know HTTP well
90
92
  rescue HttpParserError => e
93
+ @server.lowlevel_error(e, c.env)
94
+
91
95
  c.write_400
92
96
  c.close
93
97
 
@@ -95,6 +99,8 @@ module Puma
95
99
 
96
100
  @events.parse_error @server, c.env, e
97
101
  rescue StandardError => e
102
+ @server.lowlevel_error(e, c.env)
103
+
98
104
  c.write_500
99
105
  c.close
100
106
 
@@ -430,6 +430,8 @@ module Puma
430
430
 
431
431
  # SSL handshake error
432
432
  rescue MiniSSL::SSLError => e
433
+ lowlevel_error(e, client.env)
434
+
433
435
  ssl_socket = client.io
434
436
  addr = ssl_socket.peeraddr.last
435
437
  cert = ssl_socket.peercert
@@ -440,12 +442,16 @@ module Puma
440
442
 
441
443
  # The client doesn't know HTTP well
442
444
  rescue HttpParserError => e
445
+ lowlevel_error(e, client.env)
446
+
443
447
  client.write_400
444
448
 
445
449
  @events.parse_error self, client.env, e
446
450
 
447
451
  # Server error
448
452
  rescue StandardError => e
453
+ lowlevel_error(e, client.env)
454
+
449
455
  client.write_500
450
456
 
451
457
  @events.unknown_error self, e, "Read"
@@ -486,6 +492,8 @@ module Puma
486
492
  env[REQUEST_PATH] = uri.path
487
493
 
488
494
  raise "No REQUEST PATH" unless env[REQUEST_PATH]
495
+
496
+ env[QUERY_STRING] = uri.query
489
497
  end
490
498
 
491
499
  env[PATH_INFO] = env[REQUEST_PATH]
@@ -571,6 +579,14 @@ module Puma
571
579
 
572
580
  return :async
573
581
  end
582
+ rescue ThreadPool::ForceShutdown => e
583
+ @events.log "Detected force shutdown of a thread, returning 503"
584
+ @events.unknown_error self, e, "Rack app"
585
+
586
+ status = 503
587
+ headers = {}
588
+ res_body = ["Request was internally terminated early\n"]
589
+
574
590
  rescue StandardError => e
575
591
  @events.unknown_error self, e, "Rack app"
576
592
 
@@ -723,7 +739,7 @@ module Puma
723
739
  end
724
740
  private :fetch_status_code
725
741
 
726
- # Given the requset +env+ from +client+ and the partial body +body+
742
+ # Given the request +env+ from +client+ and the partial body +body+
727
743
  # plus a potential Content-Length value +cl+, finish reading
728
744
  # the body and return it.
729
745
  #
@@ -835,7 +851,13 @@ module Puma
835
851
  @events.debug "Drained #{count} additional connections."
836
852
  end
837
853
 
838
- @thread_pool.shutdown if @thread_pool
854
+ if @thread_pool
855
+ if timeout = @options[:force_shutdown_after]
856
+ @thread_pool.shutdown timeout.to_i
857
+ else
858
+ @thread_pool.shutdown
859
+ end
860
+ end
839
861
  end
840
862
 
841
863
  # Stops the acceptor thread and then causes the worker threads to finish
@@ -71,7 +71,7 @@ module Puma
71
71
  exit 1
72
72
  end
73
73
 
74
- pid = jruby_daemon_start
74
+ jruby_daemon_start
75
75
  sleep
76
76
  end
77
77
  else
@@ -5,6 +5,9 @@ module Puma
5
5
  #
6
6
  class ThreadPool
7
7
 
8
+ class ForceShutdown < RuntimeError
9
+ end
10
+
8
11
  # Maintain a minimum of +min+ and maximum of +max+ threads
9
12
  # in the pool.
10
13
  #
@@ -239,7 +242,7 @@ module Puma
239
242
 
240
243
  # Tell all threads in the pool to exit and wait for them to finish.
241
244
  #
242
- def shutdown
245
+ def shutdown(timeout=-1)
243
246
  threads = @mutex.synchronize do
244
247
  @shutdown = true
245
248
  @not_empty.broadcast
@@ -251,7 +254,38 @@ module Puma
251
254
  @workers.dup
252
255
  end
253
256
 
254
- threads.each(&:join)
257
+ case timeout
258
+ when -1
259
+ threads.each(&:join)
260
+ when 0
261
+ threads.each do |t|
262
+ t.raise ForceShutdown
263
+ end
264
+
265
+ threads.each do |t|
266
+ t.join Const::SHUTDOWN_GRACE_TIME
267
+ end
268
+ else
269
+ timeout.times do
270
+ threads.delete_if do |t|
271
+ t.join 1
272
+ end
273
+
274
+ if threads.empty?
275
+ break
276
+ else
277
+ sleep 1
278
+ end
279
+ end
280
+
281
+ threads.each do |t|
282
+ t.raise ForceShutdown
283
+ end
284
+
285
+ threads.each do |t|
286
+ t.join Const::SHUTDOWN_GRACE_TIME
287
+ end
288
+ end
255
289
 
256
290
  @spawned = 0
257
291
  @workers = []
@@ -357,7 +357,7 @@ case "$1" in
357
357
  ;;
358
358
  add)
359
359
  if [ "$#" -lt 3 ]; then
360
- echo "Please, specifiy the app's directory and the user that will run it at least."
360
+ echo "Please, specify the app's directory and the user that will run it at least."
361
361
  echo " Usage: $SCRIPTNAME add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log"
362
362
  echo " config and log are optionals."
363
363
  exit 1
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puma
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-05 00:00:00.000000000 Z
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc