puma 4.3.10 → 5.0.0.beta1
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 +58 -31
- data/LICENSE +23 -20
- data/README.md +17 -11
- data/docs/deployment.md +3 -1
- data/docs/fork_worker.md +31 -0
- data/docs/jungle/README.md +13 -0
- data/{tools → docs}/jungle/rc.d/README.md +0 -0
- data/{tools → docs}/jungle/rc.d/puma +0 -0
- data/{tools → docs}/jungle/rc.d/puma.conf +0 -0
- data/{tools → docs}/jungle/upstart/README.md +0 -0
- data/{tools → docs}/jungle/upstart/puma-manager.conf +0 -0
- data/{tools → docs}/jungle/upstart/puma.conf +0 -0
- data/docs/signals.md +1 -0
- data/docs/systemd.md +1 -63
- data/ext/puma_http11/PumaHttp11Service.java +2 -4
- data/ext/puma_http11/extconf.rb +3 -2
- data/ext/puma_http11/http11_parser.c +11 -26
- data/ext/puma_http11/http11_parser.rl +1 -3
- data/ext/puma_http11/http11_parser_common.rl +1 -1
- data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +46 -48
- data/ext/puma_http11/puma_http11.c +2 -38
- data/lib/puma/app/status.rb +16 -5
- data/lib/puma/binder.rb +62 -60
- data/lib/puma/cli.rb +7 -15
- data/lib/puma/client.rb +35 -32
- data/lib/puma/cluster.rb +179 -74
- data/lib/puma/configuration.rb +30 -42
- data/lib/puma/const.rb +2 -3
- data/lib/puma/control_cli.rb +27 -17
- data/lib/puma/detect.rb +8 -0
- data/lib/puma/dsl.rb +70 -34
- data/lib/puma/io_buffer.rb +9 -2
- data/lib/puma/jruby_restart.rb +0 -58
- data/lib/puma/launcher.rb +41 -29
- data/lib/puma/minissl.rb +13 -8
- data/lib/puma/null_io.rb +1 -1
- data/lib/puma/plugin.rb +1 -10
- data/lib/puma/rack/builder.rb +0 -4
- data/lib/puma/reactor.rb +6 -1
- data/lib/puma/runner.rb +5 -34
- data/lib/puma/server.rb +70 -190
- data/lib/puma/single.rb +7 -64
- data/lib/puma/state_file.rb +5 -2
- data/lib/puma/thread_pool.rb +85 -47
- data/lib/puma.rb +4 -0
- data/lib/rack/handler/puma.rb +1 -3
- data/tools/{docker/Dockerfile → Dockerfile} +0 -0
- metadata +22 -26
- data/docs/tcp_mode.md +0 -96
- data/ext/puma_http11/io_buffer.c +0 -155
- data/ext/puma_http11/org/jruby/puma/IOBuffer.java +0 -72
- data/lib/puma/tcp_logger.rb +0 -41
- data/tools/jungle/README.md +0 -19
- data/tools/jungle/init.d/README.md +0 -61
- data/tools/jungle/init.d/puma +0 -421
- data/tools/jungle/init.d/run-puma +0 -18
data/lib/puma/server.rb
CHANGED
@@ -11,6 +11,7 @@ require 'puma/client'
|
|
11
11
|
require 'puma/binder'
|
12
12
|
require 'puma/accept_nonblock'
|
13
13
|
require 'puma/util'
|
14
|
+
require 'puma/io_buffer'
|
14
15
|
|
15
16
|
require 'puma/puma_http11'
|
16
17
|
|
@@ -36,6 +37,7 @@ module Puma
|
|
36
37
|
|
37
38
|
attr_reader :thread
|
38
39
|
attr_reader :events
|
40
|
+
attr_reader :requests_count
|
39
41
|
attr_accessor :app
|
40
42
|
|
41
43
|
attr_accessor :min_threads
|
@@ -57,8 +59,7 @@ module Puma
|
|
57
59
|
@app = app
|
58
60
|
@events = events
|
59
61
|
|
60
|
-
@check, @notify =
|
61
|
-
|
62
|
+
@check, @notify = nil
|
62
63
|
@status = :stop
|
63
64
|
|
64
65
|
@min_threads = 0
|
@@ -85,20 +86,18 @@ module Puma
|
|
85
86
|
@mode = :http
|
86
87
|
|
87
88
|
@precheck_closing = true
|
89
|
+
|
90
|
+
@requests_count = 0
|
88
91
|
end
|
89
92
|
|
90
93
|
attr_accessor :binder, :leak_stack_on_error, :early_hints
|
91
94
|
|
92
|
-
def_delegators :@binder, :add_tcp_listener, :add_ssl_listener, :add_unix_listener, :
|
95
|
+
def_delegators :@binder, :add_tcp_listener, :add_ssl_listener, :add_unix_listener, :connected_ports
|
93
96
|
|
94
97
|
def inherit_binder(bind)
|
95
98
|
@binder = bind
|
96
99
|
end
|
97
100
|
|
98
|
-
def tcp_mode!
|
99
|
-
@mode = :tcp
|
100
|
-
end
|
101
|
-
|
102
101
|
# On Linux, use TCP_CORK to better control how the TCP stack
|
103
102
|
# packetizes our stream. This improves both latency and throughput.
|
104
103
|
#
|
@@ -172,107 +171,6 @@ module Puma
|
|
172
171
|
@thread_pool and @thread_pool.pool_capacity
|
173
172
|
end
|
174
173
|
|
175
|
-
# Lopez Mode == raw tcp apps
|
176
|
-
|
177
|
-
def run_lopez_mode(background=true)
|
178
|
-
@thread_pool = ThreadPool.new(@min_threads,
|
179
|
-
@max_threads,
|
180
|
-
Hash) do |client, tl|
|
181
|
-
|
182
|
-
io = client.to_io
|
183
|
-
addr = io.peeraddr.last
|
184
|
-
|
185
|
-
if addr.empty?
|
186
|
-
# Set unix socket addrs to localhost
|
187
|
-
addr = "127.0.0.1:0"
|
188
|
-
else
|
189
|
-
addr = "#{addr}:#{io.peeraddr[1]}"
|
190
|
-
end
|
191
|
-
|
192
|
-
env = { 'thread' => tl, REMOTE_ADDR => addr }
|
193
|
-
|
194
|
-
begin
|
195
|
-
@app.call env, client.to_io
|
196
|
-
rescue Object => e
|
197
|
-
STDERR.puts "! Detected exception at toplevel: #{e.message} (#{e.class})"
|
198
|
-
STDERR.puts e.backtrace
|
199
|
-
end
|
200
|
-
|
201
|
-
client.close unless env['detach']
|
202
|
-
end
|
203
|
-
|
204
|
-
@events.fire :state, :running
|
205
|
-
|
206
|
-
if background
|
207
|
-
@thread = Thread.new do
|
208
|
-
Puma.set_thread_name "server"
|
209
|
-
handle_servers_lopez_mode
|
210
|
-
end
|
211
|
-
return @thread
|
212
|
-
else
|
213
|
-
handle_servers_lopez_mode
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def handle_servers_lopez_mode
|
218
|
-
begin
|
219
|
-
check = @check
|
220
|
-
sockets = [check] + @binder.ios
|
221
|
-
pool = @thread_pool
|
222
|
-
|
223
|
-
while @status == :run
|
224
|
-
begin
|
225
|
-
ios = IO.select sockets
|
226
|
-
ios.first.each do |sock|
|
227
|
-
if sock == check
|
228
|
-
break if handle_check
|
229
|
-
else
|
230
|
-
begin
|
231
|
-
if io = sock.accept_nonblock
|
232
|
-
client = Client.new io, nil
|
233
|
-
pool << client
|
234
|
-
end
|
235
|
-
rescue SystemCallError
|
236
|
-
# nothing
|
237
|
-
rescue Errno::ECONNABORTED
|
238
|
-
# client closed the socket even before accept
|
239
|
-
begin
|
240
|
-
io.close
|
241
|
-
rescue
|
242
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
rescue Object => e
|
248
|
-
@events.unknown_error self, e, "Listen loop"
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
@events.fire :state, @status
|
253
|
-
|
254
|
-
graceful_shutdown if @status == :stop || @status == :restart
|
255
|
-
|
256
|
-
rescue Exception => e
|
257
|
-
STDERR.puts "Exception handling servers: #{e.message} (#{e.class})"
|
258
|
-
STDERR.puts e.backtrace
|
259
|
-
ensure
|
260
|
-
begin
|
261
|
-
@check.close
|
262
|
-
rescue
|
263
|
-
Thread.current.purge_interrupt_queue if Thread.current.respond_to? :purge_interrupt_queue
|
264
|
-
end
|
265
|
-
|
266
|
-
# Prevent can't modify frozen IOError (RuntimeError)
|
267
|
-
begin
|
268
|
-
@notify.close
|
269
|
-
rescue IOError
|
270
|
-
# no biggy
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
@events.fire :state, :done
|
275
|
-
end
|
276
174
|
# Runs the server.
|
277
175
|
#
|
278
176
|
# If +background+ is true (the default) then a thread is spun
|
@@ -286,15 +184,9 @@ module Puma
|
|
286
184
|
|
287
185
|
@status = :run
|
288
186
|
|
289
|
-
if @mode == :tcp
|
290
|
-
return run_lopez_mode(background)
|
291
|
-
end
|
292
|
-
|
293
|
-
queue_requests = @queue_requests
|
294
|
-
|
295
187
|
@thread_pool = ThreadPool.new(@min_threads,
|
296
188
|
@max_threads,
|
297
|
-
IOBuffer) do |client, buffer|
|
189
|
+
::Puma::IOBuffer) do |client, buffer|
|
298
190
|
|
299
191
|
# Advertise this server into the thread
|
300
192
|
Thread.current[ThreadLocalKey] = self
|
@@ -302,10 +194,10 @@ module Puma
|
|
302
194
|
process_now = false
|
303
195
|
|
304
196
|
begin
|
305
|
-
if queue_requests
|
197
|
+
if @queue_requests
|
306
198
|
process_now = client.eagerly_finish
|
307
199
|
else
|
308
|
-
client.finish
|
200
|
+
client.finish(@first_data_timeout)
|
309
201
|
process_now = true
|
310
202
|
end
|
311
203
|
rescue MiniSSL::SSLError => e
|
@@ -331,11 +223,14 @@ module Puma
|
|
331
223
|
@reactor.add client
|
332
224
|
end
|
333
225
|
end
|
226
|
+
|
227
|
+
process_now
|
334
228
|
end
|
335
229
|
|
230
|
+
@thread_pool.out_of_band_hook = @options[:out_of_band]
|
336
231
|
@thread_pool.clean_thread_locals = @options[:clean_thread_locals]
|
337
232
|
|
338
|
-
if queue_requests
|
233
|
+
if @queue_requests
|
339
234
|
@reactor = Reactor.new self, @thread_pool
|
340
235
|
@reactor.run_in_thread
|
341
236
|
end
|
@@ -362,6 +257,7 @@ module Puma
|
|
362
257
|
end
|
363
258
|
|
364
259
|
def handle_servers
|
260
|
+
@check, @notify = Puma::Util.pipe unless @notify
|
365
261
|
begin
|
366
262
|
check = @check
|
367
263
|
sockets = [check] + @binder.ios
|
@@ -386,6 +282,10 @@ module Puma
|
|
386
282
|
break if handle_check
|
387
283
|
else
|
388
284
|
begin
|
285
|
+
pool.wait_until_not_full
|
286
|
+
pool.wait_for_less_busy_worker(
|
287
|
+
@options[:wait_for_less_busy_worker].to_f)
|
288
|
+
|
389
289
|
if io = sock.accept_nonblock
|
390
290
|
client = Client.new io, @binder.env(sock)
|
391
291
|
if remote_addr_value
|
@@ -395,10 +295,6 @@ module Puma
|
|
395
295
|
end
|
396
296
|
|
397
297
|
pool << client
|
398
|
-
busy_threads = pool.wait_until_not_full
|
399
|
-
if busy_threads == 0
|
400
|
-
@options[:out_of_band].each(&:call) if @options[:out_of_band]
|
401
|
-
end
|
402
298
|
end
|
403
299
|
rescue SystemCallError
|
404
300
|
# nothing
|
@@ -419,17 +315,20 @@ module Puma
|
|
419
315
|
|
420
316
|
@events.fire :state, @status
|
421
317
|
|
422
|
-
graceful_shutdown if @status == :stop || @status == :restart
|
423
318
|
if queue_requests
|
319
|
+
@queue_requests = false
|
424
320
|
@reactor.clear!
|
425
321
|
@reactor.shutdown
|
426
322
|
end
|
323
|
+
graceful_shutdown if @status == :stop || @status == :restart
|
427
324
|
rescue Exception => e
|
428
325
|
STDERR.puts "Exception handling servers: #{e.message} (#{e.class})"
|
429
326
|
STDERR.puts e.backtrace
|
430
327
|
ensure
|
431
|
-
@check.close
|
328
|
+
@check.close unless @check.closed? # Ruby 2.2 issue
|
432
329
|
@notify.close
|
330
|
+
@notify = nil
|
331
|
+
@check = nil
|
433
332
|
end
|
434
333
|
|
435
334
|
@events.fire :state, :done
|
@@ -476,29 +375,24 @@ module Puma
|
|
476
375
|
close_socket = false
|
477
376
|
return
|
478
377
|
when true
|
479
|
-
return unless @queue_requests
|
480
378
|
buffer.reset
|
481
379
|
|
482
380
|
ThreadPool.clean_thread_locals if clean_thread_locals
|
483
381
|
|
484
382
|
requests += 1
|
485
383
|
|
486
|
-
# Closing keepalive sockets after they've made a reasonable
|
487
|
-
# number of requests allows Puma to service many connections
|
488
|
-
# fairly, even when the number of concurrent connections exceeds
|
489
|
-
# the size of the threadpool. It also allows cluster mode Pumas
|
490
|
-
# to keep load evenly distributed across workers, because clients
|
491
|
-
# are randomly assigned a new worker when opening a new connection.
|
492
|
-
#
|
493
|
-
# Previously, Puma would kick connections in this conditional back
|
494
|
-
# to the reactor. However, because this causes the todo set to increase
|
495
|
-
# in size, the wait_until_full mutex would never unlock, leaving
|
496
|
-
# any additional connections unserviced.
|
497
|
-
break if requests >= MAX_FAST_INLINE
|
498
|
-
|
499
384
|
check_for_more_data = @status == :run
|
500
385
|
|
386
|
+
if requests >= MAX_FAST_INLINE
|
387
|
+
# This will mean that reset will only try to use the data it already
|
388
|
+
# has buffered and won't try to read more data. What this means is that
|
389
|
+
# every client, independent of their request speed, gets treated like a slow
|
390
|
+
# one once every MAX_FAST_INLINE requests.
|
391
|
+
check_for_more_data = false
|
392
|
+
end
|
393
|
+
|
501
394
|
unless client.reset(check_for_more_data)
|
395
|
+
return unless @queue_requests
|
502
396
|
close_socket = false
|
503
397
|
client.set_timeout @persistent_timeout
|
504
398
|
@reactor.add client
|
@@ -631,6 +525,8 @@ module Puma
|
|
631
525
|
#
|
632
526
|
# Finally, it'll return +true+ on keep-alive connections.
|
633
527
|
def handle_request(req, lines)
|
528
|
+
@requests_count +=1
|
529
|
+
|
634
530
|
env = req.env
|
635
531
|
client = req.io
|
636
532
|
|
@@ -677,37 +573,6 @@ module Puma
|
|
677
573
|
}
|
678
574
|
end
|
679
575
|
|
680
|
-
# Fixup any headers with , in the name to have _ now. We emit
|
681
|
-
# headers with , in them during the parse phase to avoid ambiguity
|
682
|
-
# with the - to _ conversion for critical headers. But here for
|
683
|
-
# compatibility, we'll convert them back. This code is written to
|
684
|
-
# avoid allocation in the common case (ie there are no headers
|
685
|
-
# with , in their names), that's why it has the extra conditionals.
|
686
|
-
|
687
|
-
to_delete = nil
|
688
|
-
to_add = nil
|
689
|
-
|
690
|
-
env.each do |k,v|
|
691
|
-
if k.start_with?("HTTP_") and k.include?(",") and k != "HTTP_TRANSFER,ENCODING"
|
692
|
-
if to_delete
|
693
|
-
to_delete << k
|
694
|
-
else
|
695
|
-
to_delete = [k]
|
696
|
-
end
|
697
|
-
|
698
|
-
unless to_add
|
699
|
-
to_add = {}
|
700
|
-
end
|
701
|
-
|
702
|
-
to_add[k.tr(",", "_")] = v
|
703
|
-
end
|
704
|
-
end
|
705
|
-
|
706
|
-
if to_delete
|
707
|
-
to_delete.each { |k| env.delete(k) }
|
708
|
-
env.merge! to_add
|
709
|
-
end
|
710
|
-
|
711
576
|
# A rack extension. If the app writes #call'ables to this
|
712
577
|
# array, we will invoke them when the request is done.
|
713
578
|
#
|
@@ -729,17 +594,14 @@ module Puma
|
|
729
594
|
return :async
|
730
595
|
end
|
731
596
|
rescue ThreadPool::ForceShutdown => e
|
732
|
-
@events.
|
733
|
-
@events.
|
734
|
-
|
735
|
-
status = 503
|
736
|
-
headers = {}
|
737
|
-
res_body = ["Request was internally terminated early\n"]
|
597
|
+
@events.unknown_error self, e, "Rack app", env
|
598
|
+
@events.log "Detected force shutdown of a thread"
|
738
599
|
|
600
|
+
status, headers, res_body = lowlevel_error(e, env, 503)
|
739
601
|
rescue Exception => e
|
740
602
|
@events.unknown_error self, e, "Rack app", env
|
741
603
|
|
742
|
-
status, headers, res_body = lowlevel_error(e, env)
|
604
|
+
status, headers, res_body = lowlevel_error(e, env, 500)
|
743
605
|
end
|
744
606
|
|
745
607
|
content_length = nil
|
@@ -754,10 +616,10 @@ module Puma
|
|
754
616
|
line_ending = LINE_END
|
755
617
|
colon = COLON
|
756
618
|
|
757
|
-
http_11 =
|
619
|
+
http_11 = env[HTTP_VERSION] == HTTP_11
|
620
|
+
if http_11
|
758
621
|
allow_chunked = true
|
759
622
|
keep_alive = env.fetch(HTTP_CONNECTION, "").downcase != CLOSE
|
760
|
-
include_keepalive_header = false
|
761
623
|
|
762
624
|
# An optimization. The most common response is 200, so we can
|
763
625
|
# reply with the proper 200 status without having to compute
|
@@ -771,11 +633,9 @@ module Puma
|
|
771
633
|
|
772
634
|
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
|
773
635
|
end
|
774
|
-
true
|
775
636
|
else
|
776
637
|
allow_chunked = false
|
777
638
|
keep_alive = env.fetch(HTTP_CONNECTION, "").downcase == KEEP_ALIVE
|
778
|
-
include_keepalive_header = keep_alive
|
779
639
|
|
780
640
|
# Same optimization as above for HTTP/1.1
|
781
641
|
#
|
@@ -787,9 +647,12 @@ module Puma
|
|
787
647
|
|
788
648
|
no_body ||= status < 200 || STATUS_WITH_NO_ENTITY_BODY[status]
|
789
649
|
end
|
790
|
-
false
|
791
650
|
end
|
792
651
|
|
652
|
+
# regardless of what the client wants, we always close the connection
|
653
|
+
# if running without request queueing
|
654
|
+
keep_alive &&= @queue_requests
|
655
|
+
|
793
656
|
response_hijack = nil
|
794
657
|
|
795
658
|
headers.each do |k, vs|
|
@@ -816,10 +679,15 @@ module Puma
|
|
816
679
|
end
|
817
680
|
end
|
818
681
|
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
682
|
+
# HTTP/1.1 & 1.0 assume different defaults:
|
683
|
+
# - HTTP 1.0 assumes the connection will be closed if not specified
|
684
|
+
# - HTTP 1.1 assumes the connection will be kept alive if not specified.
|
685
|
+
# Only set the header if we're doing something which is not the default
|
686
|
+
# for this protocol version
|
687
|
+
if http_11
|
688
|
+
lines << CONNECTION_CLOSE if !keep_alive
|
689
|
+
else
|
690
|
+
lines << CONNECTION_KEEP_ALIVE if keep_alive
|
823
691
|
end
|
824
692
|
|
825
693
|
if no_body
|
@@ -946,19 +814,21 @@ module Puma
|
|
946
814
|
|
947
815
|
# A fallback rack response if +@app+ raises as exception.
|
948
816
|
#
|
949
|
-
def lowlevel_error(e, env)
|
817
|
+
def lowlevel_error(e, env, status=500)
|
950
818
|
if handler = @options[:lowlevel_error_handler]
|
951
819
|
if handler.arity == 1
|
952
820
|
return handler.call(e)
|
953
|
-
|
821
|
+
elsif handler.arity == 2
|
954
822
|
return handler.call(e, env)
|
823
|
+
else
|
824
|
+
return handler.call(e, env, status)
|
955
825
|
end
|
956
826
|
end
|
957
827
|
|
958
828
|
if @leak_stack_on_error
|
959
|
-
[
|
829
|
+
[status, {}, ["Puma caught this error: #{e.message} (#{e.class})\n#{e.backtrace.join("\n")}"]]
|
960
830
|
else
|
961
|
-
[
|
831
|
+
[status, {}, ["An unhandled lowlevel error occurred. The application logs may have details.\n"]]
|
962
832
|
end
|
963
833
|
end
|
964
834
|
|
@@ -1016,6 +886,7 @@ module Puma
|
|
1016
886
|
end
|
1017
887
|
|
1018
888
|
def notify_safely(message)
|
889
|
+
@check, @notify = Puma::Util.pipe unless @notify
|
1019
890
|
begin
|
1020
891
|
@notify << message
|
1021
892
|
rescue IOError
|
@@ -1045,8 +916,9 @@ module Puma
|
|
1045
916
|
@thread.join if @thread && sync
|
1046
917
|
end
|
1047
918
|
|
1048
|
-
def begin_restart
|
919
|
+
def begin_restart(sync=false)
|
1049
920
|
notify_safely(RESTART_COMMAND)
|
921
|
+
@thread.join if @thread && sync
|
1050
922
|
end
|
1051
923
|
|
1052
924
|
def fast_write(io, str)
|
@@ -1084,5 +956,13 @@ module Puma
|
|
1084
956
|
HTTP_INJECTION_REGEX =~ header_value.to_s
|
1085
957
|
end
|
1086
958
|
private :possible_header_injection?
|
959
|
+
|
960
|
+
# List of methods invoked by #stats.
|
961
|
+
STAT_METHODS = [:backlog, :running, :pool_capacity, :max_threads, :requests_count].freeze
|
962
|
+
|
963
|
+
# Returns a hash of stats about the running server for reporting purposes.
|
964
|
+
def stats
|
965
|
+
STAT_METHODS.map {|name| [name, send(name) || 0]}.to_h
|
966
|
+
end
|
1087
967
|
end
|
1088
968
|
end
|
data/lib/puma/single.rb
CHANGED
@@ -14,11 +14,9 @@ module Puma
|
|
14
14
|
# that this inherits from.
|
15
15
|
class Single < Runner
|
16
16
|
def stats
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
m = @server.max_threads || 0
|
21
|
-
%Q!{ "started_at": "#{@started_at.utc.iso8601}", "backlog": #{b}, "running": #{r}, "pool_capacity": #{t}, "max_threads": #{m} }!
|
17
|
+
{
|
18
|
+
started_at: @started_at.utc.iso8601
|
19
|
+
}.merge(@server.stats)
|
22
20
|
end
|
23
21
|
|
24
22
|
def restart
|
@@ -39,64 +37,10 @@ module Puma
|
|
39
37
|
@server.stop(true) if @server
|
40
38
|
end
|
41
39
|
|
42
|
-
def jruby_daemon?
|
43
|
-
daemon? and Puma.jruby?
|
44
|
-
end
|
45
|
-
|
46
|
-
def jruby_daemon_start
|
47
|
-
require 'puma/jruby_restart'
|
48
|
-
JRubyRestart.daemon_start(@restart_dir, @launcher.restart_args)
|
49
|
-
end
|
50
|
-
|
51
40
|
def run
|
52
|
-
already_daemon = false
|
53
|
-
|
54
|
-
if jruby_daemon?
|
55
|
-
require 'puma/jruby_restart'
|
56
|
-
|
57
|
-
if JRubyRestart.daemon?
|
58
|
-
# load and bind before redirecting IO so errors show up on stdout/stderr
|
59
|
-
load_and_bind
|
60
|
-
redirect_io
|
61
|
-
end
|
62
|
-
|
63
|
-
already_daemon = JRubyRestart.daemon_init
|
64
|
-
end
|
65
|
-
|
66
41
|
output_header "single"
|
67
42
|
|
68
|
-
|
69
|
-
if already_daemon
|
70
|
-
JRubyRestart.perm_daemonize
|
71
|
-
else
|
72
|
-
pid = nil
|
73
|
-
|
74
|
-
Signal.trap "SIGUSR2" do
|
75
|
-
log "* Started new process #{pid} as daemon..."
|
76
|
-
|
77
|
-
# Must use exit! so we don't unwind and run the ensures
|
78
|
-
# that will be run by the new child (such as deleting the
|
79
|
-
# pidfile)
|
80
|
-
exit!(true)
|
81
|
-
end
|
82
|
-
|
83
|
-
Signal.trap "SIGCHLD" do
|
84
|
-
log "! Error starting new process as daemon, exiting"
|
85
|
-
exit 1
|
86
|
-
end
|
87
|
-
|
88
|
-
jruby_daemon_start
|
89
|
-
sleep
|
90
|
-
end
|
91
|
-
else
|
92
|
-
if daemon?
|
93
|
-
log "* Daemonizing..."
|
94
|
-
Process.daemon(true)
|
95
|
-
redirect_io
|
96
|
-
end
|
97
|
-
|
98
|
-
load_and_bind
|
99
|
-
end
|
43
|
+
load_and_bind
|
100
44
|
|
101
45
|
Plugins.fire_background
|
102
46
|
|
@@ -106,10 +50,9 @@ module Puma
|
|
106
50
|
|
107
51
|
@server = server = start_server
|
108
52
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
end
|
53
|
+
|
54
|
+
log "Use Ctrl-C to stop"
|
55
|
+
redirect_io
|
113
56
|
|
114
57
|
@launcher.events.fire_on_booted!
|
115
58
|
|
data/lib/puma/state_file.rb
CHANGED
@@ -8,8 +8,11 @@ module Puma
|
|
8
8
|
@options = {}
|
9
9
|
end
|
10
10
|
|
11
|
-
def save(path)
|
12
|
-
File.
|
11
|
+
def save(path, permission = nil)
|
12
|
+
File.open(path, "w") do |file|
|
13
|
+
file.chmod(permission) if permission
|
14
|
+
file.write(YAML.dump(@options))
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def load(path)
|