puma 3.0.0.rc1 → 5.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/{History.txt → History.md} +703 -70
- data/LICENSE +23 -20
- data/README.md +173 -163
- data/docs/architecture.md +37 -0
- data/{DEPLOYMENT.md → docs/deployment.md} +28 -6
- data/docs/fork_worker.md +31 -0
- 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/jungle/README.md +13 -0
- data/docs/jungle/rc.d/README.md +74 -0
- data/docs/jungle/rc.d/puma +61 -0
- data/docs/jungle/rc.d/puma.conf +10 -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 +1 -1
- data/docs/nginx.md +2 -2
- data/docs/plugins.md +38 -0
- data/docs/restart.md +41 -0
- data/docs/signals.md +57 -3
- data/docs/systemd.md +228 -0
- data/ext/puma_http11/PumaHttp11Service.java +2 -2
- data/ext/puma_http11/extconf.rb +16 -0
- data/ext/puma_http11/http11_parser.c +287 -468
- data/ext/puma_http11/http11_parser.h +1 -0
- data/ext/puma_http11/http11_parser.java.rl +21 -37
- data/ext/puma_http11/http11_parser.rl +10 -9
- data/ext/puma_http11/http11_parser_common.rl +4 -4
- data/ext/puma_http11/mini_ssl.c +159 -10
- data/ext/puma_http11/org/jruby/puma/Http11.java +108 -116
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +99 -132
- data/ext/puma_http11/org/jruby/puma/MiniSSL.java +30 -6
- data/ext/puma_http11/puma_http11.c +6 -38
- data/lib/puma.rb +25 -5
- data/lib/puma/accept_nonblock.rb +7 -1
- data/lib/puma/app/status.rb +53 -26
- data/lib/puma/binder.rb +150 -119
- data/lib/puma/cli.rb +56 -38
- data/lib/puma/client.rb +277 -80
- data/lib/puma/cluster.rb +326 -130
- data/lib/puma/commonlogger.rb +21 -20
- data/lib/puma/configuration.rb +160 -161
- data/lib/puma/const.rb +50 -47
- data/lib/puma/control_cli.rb +104 -63
- data/lib/puma/detect.rb +13 -1
- data/lib/puma/dsl.rb +463 -114
- data/lib/puma/events.rb +22 -13
- data/lib/puma/io_buffer.rb +9 -5
- data/lib/puma/jruby_restart.rb +2 -59
- data/lib/puma/launcher.rb +195 -105
- data/lib/puma/minissl.rb +110 -4
- data/lib/puma/minissl/context_builder.rb +76 -0
- data/lib/puma/null_io.rb +9 -14
- data/lib/puma/plugin.rb +32 -12
- data/lib/puma/plugin/tmp_restart.rb +19 -6
- data/lib/puma/rack/builder.rb +7 -5
- data/lib/puma/rack/urlmap.rb +11 -8
- data/lib/puma/rack_default.rb +2 -0
- data/lib/puma/reactor.rb +242 -32
- data/lib/puma/runner.rb +41 -30
- data/lib/puma/server.rb +265 -183
- data/lib/puma/single.rb +22 -63
- data/lib/puma/state_file.rb +9 -2
- data/lib/puma/thread_pool.rb +179 -68
- data/lib/puma/util.rb +3 -11
- data/lib/rack/handler/puma.rb +60 -11
- data/tools/Dockerfile +16 -0
- data/tools/trickletest.rb +1 -2
- metadata +35 -99
- data/COPYING +0 -55
- data/Gemfile +0 -13
- data/Manifest.txt +0 -79
- data/Rakefile +0 -158
- data/docs/config.md +0 -0
- data/ext/puma_http11/io_buffer.c +0 -155
- data/lib/puma/capistrano.rb +0 -94
- data/lib/puma/compat.rb +0 -18
- data/lib/puma/convenient.rb +0 -23
- data/lib/puma/daemon_ext.rb +0 -31
- data/lib/puma/delegation.rb +0 -11
- data/lib/puma/java_io_buffer.rb +0 -45
- data/lib/puma/rack/backports/uri/common_18.rb +0 -56
- data/lib/puma/rack/backports/uri/common_192.rb +0 -52
- data/lib/puma/rack/backports/uri/common_193.rb +0 -29
- data/lib/puma/tcp_logger.rb +0 -32
- data/puma.gemspec +0 -52
- data/tools/jungle/README.md +0 -9
- data/tools/jungle/init.d/README.md +0 -54
- data/tools/jungle/init.d/puma +0 -394
- data/tools/jungle/init.d/run-puma +0 -3
data/lib/puma/events.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'puma/const'
|
4
|
+
require "puma/null_io"
|
2
5
|
require 'stringio'
|
3
6
|
|
4
7
|
module Puma
|
@@ -34,8 +37,6 @@ module Puma
|
|
34
37
|
|
35
38
|
@debug = ENV.key? 'PUMA_DEBUG'
|
36
39
|
|
37
|
-
@on_booted = []
|
38
|
-
|
39
40
|
@hooks = Hash.new { |h,k| h[k] = [] }
|
40
41
|
end
|
41
42
|
|
@@ -48,7 +49,7 @@ module Puma
|
|
48
49
|
@hooks[hook].each { |t| t.call(*args) }
|
49
50
|
end
|
50
51
|
|
51
|
-
# Register a
|
52
|
+
# Register a callback for a given hook
|
52
53
|
#
|
53
54
|
def register(hook, obj=nil, &blk)
|
54
55
|
if obj and blk
|
@@ -92,8 +93,10 @@ module Puma
|
|
92
93
|
# parsing exception.
|
93
94
|
#
|
94
95
|
def parse_error(server, env, error)
|
95
|
-
@stderr.puts "#{Time.now}: HTTP parse error, malformed request
|
96
|
-
|
96
|
+
@stderr.puts "#{Time.now}: HTTP parse error, malformed request " \
|
97
|
+
"(#{env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR]}#{env[REQUEST_PATH]}): " \
|
98
|
+
"#{error.inspect}" \
|
99
|
+
"\n---\n"
|
97
100
|
end
|
98
101
|
|
99
102
|
# An SSL error has occurred.
|
@@ -106,24 +109,30 @@ module Puma
|
|
106
109
|
end
|
107
110
|
|
108
111
|
# An unknown error has occurred.
|
109
|
-
# +server+ is the Server object, +
|
110
|
-
#
|
112
|
+
# +server+ is the Server object, +error+ an exception object,
|
113
|
+
# +kind+ some additional info, and +env+ the request.
|
111
114
|
#
|
112
|
-
def unknown_error(server, error, kind="Unknown")
|
115
|
+
def unknown_error(server, error, kind="Unknown", env=nil)
|
113
116
|
if error.respond_to? :render
|
114
117
|
error.render "#{Time.now}: #{kind} error", @stderr
|
115
118
|
else
|
116
|
-
|
117
|
-
|
119
|
+
if env
|
120
|
+
string_block = [ "#{Time.now}: #{kind} error handling request { #{env['REQUEST_METHOD']} #{env['PATH_INFO']} }" ]
|
121
|
+
string_block << error.inspect
|
122
|
+
else
|
123
|
+
string_block = [ "#{Time.now}: #{kind} error: #{error.inspect}" ]
|
124
|
+
end
|
125
|
+
string_block << error.backtrace
|
126
|
+
@stderr.puts string_block.join("\n")
|
118
127
|
end
|
119
128
|
end
|
120
129
|
|
121
|
-
def on_booted(&
|
122
|
-
|
130
|
+
def on_booted(&block)
|
131
|
+
register(:on_booted, &block)
|
123
132
|
end
|
124
133
|
|
125
134
|
def fire_on_booted!
|
126
|
-
|
135
|
+
fire(:on_booted)
|
127
136
|
end
|
128
137
|
|
129
138
|
DEFAULT = new(STDOUT, STDERR)
|
data/lib/puma/io_buffer.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module Puma
|
4
|
+
class IOBuffer < String
|
5
|
+
def append(*args)
|
6
|
+
args.each { |a| concat(a) }
|
7
|
+
end
|
8
|
+
|
9
|
+
alias reset clear
|
10
|
+
end
|
7
11
|
end
|
data/lib/puma/jruby_restart.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'ffi'
|
2
4
|
|
3
5
|
module Puma
|
@@ -20,64 +22,5 @@ module Puma
|
|
20
22
|
execlp(cmd, *argv)
|
21
23
|
raise SystemCallError.new(FFI.errno)
|
22
24
|
end
|
23
|
-
|
24
|
-
PermKey = 'PUMA_DAEMON_PERM'
|
25
|
-
RestartKey = 'PUMA_DAEMON_RESTART'
|
26
|
-
|
27
|
-
# Called to tell things "Your now always in daemon mode,
|
28
|
-
# don't try to reenter it."
|
29
|
-
#
|
30
|
-
def self.perm_daemonize
|
31
|
-
ENV[PermKey] = "1"
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.daemon?
|
35
|
-
ENV.key?(PermKey) || ENV.key?(RestartKey)
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.daemon_init
|
39
|
-
return true if ENV.key?(PermKey)
|
40
|
-
|
41
|
-
return false unless ENV.key? RestartKey
|
42
|
-
|
43
|
-
master = ENV[RestartKey]
|
44
|
-
|
45
|
-
# In case the master disappears early
|
46
|
-
begin
|
47
|
-
Process.kill "SIGUSR2", master.to_i
|
48
|
-
rescue SystemCallError => e
|
49
|
-
end
|
50
|
-
|
51
|
-
ENV[RestartKey] = ""
|
52
|
-
|
53
|
-
setsid
|
54
|
-
|
55
|
-
null = File.open "/dev/null", "w+"
|
56
|
-
STDIN.reopen null
|
57
|
-
STDOUT.reopen null
|
58
|
-
STDERR.reopen null
|
59
|
-
|
60
|
-
true
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.daemon_start(dir, argv)
|
64
|
-
ENV['PUMA_DAEMON_RESTART'] = Process.pid.to_s
|
65
|
-
|
66
|
-
if k = ENV['PUMA_JRUBY_DAEMON_OPTS']
|
67
|
-
ENV['JRUBY_OPTS'] = k
|
68
|
-
end
|
69
|
-
|
70
|
-
cmd = argv.first
|
71
|
-
argv = ([:string] * argv.size).zip(argv).flatten
|
72
|
-
argv << :string
|
73
|
-
argv << nil
|
74
|
-
|
75
|
-
chdir(dir)
|
76
|
-
ret = fork
|
77
|
-
return ret if ret != 0
|
78
|
-
execlp(cmd, *argv)
|
79
|
-
raise SystemCallError.new(FFI.errno)
|
80
|
-
end
|
81
25
|
end
|
82
26
|
end
|
83
|
-
|
data/lib/puma/launcher.rb
CHANGED
@@ -1,18 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'puma/
|
4
|
-
require 'puma/binder'
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puma/events'
|
5
4
|
require 'puma/detect'
|
6
|
-
require 'puma/daemon_ext'
|
7
|
-
require 'puma/util'
|
8
|
-
require 'puma/single'
|
9
5
|
require 'puma/cluster'
|
10
|
-
require 'puma/
|
11
|
-
|
12
|
-
require 'puma/
|
6
|
+
require 'puma/single'
|
7
|
+
require 'puma/const'
|
8
|
+
require 'puma/binder'
|
13
9
|
|
14
10
|
module Puma
|
15
|
-
#
|
11
|
+
# Puma::Launcher is the single entry point for starting a Puma server based on user
|
16
12
|
# configuration. It is responsible for taking user supplied arguments and resolving them
|
17
13
|
# with configuration in `config/puma.rb` or `config/puma/<env>.rb`.
|
18
14
|
#
|
@@ -37,13 +33,13 @@ module Puma
|
|
37
33
|
#
|
38
34
|
# Examples:
|
39
35
|
#
|
40
|
-
# conf = Puma::Configuration.new do |
|
41
|
-
#
|
42
|
-
#
|
36
|
+
# conf = Puma::Configuration.new do |user_config|
|
37
|
+
# user_config.threads 1, 10
|
38
|
+
# user_config.app do |env|
|
43
39
|
# [200, {}, ["hello world"]]
|
44
40
|
# end
|
45
41
|
# end
|
46
|
-
# Puma::Launcher.new(conf,
|
42
|
+
# Puma::Launcher.new(conf, events: Puma::Events.stdio).run
|
47
43
|
def initialize(conf, launcher_args={})
|
48
44
|
@runner = nil
|
49
45
|
@events = launcher_args[:events] || Events::DEFAULT
|
@@ -52,9 +48,8 @@ module Puma
|
|
52
48
|
@config = conf
|
53
49
|
|
54
50
|
@binder = Binder.new(@events)
|
55
|
-
@binder.
|
56
|
-
|
57
|
-
generate_restart_data
|
51
|
+
@binder.create_inherited_fds(ENV).each { |k| ENV.delete k }
|
52
|
+
@binder.create_activated_fds(ENV).each { |k| ENV.delete k }
|
58
53
|
|
59
54
|
@environment = conf.environment
|
60
55
|
|
@@ -64,17 +59,18 @@ module Puma
|
|
64
59
|
@config.load
|
65
60
|
|
66
61
|
@options = @config.options
|
62
|
+
@config.clamp
|
67
63
|
|
68
|
-
|
69
|
-
|
70
|
-
end
|
64
|
+
@events.formatter = Events::PidFormatter.new if clustered?
|
65
|
+
@events.formatter = options[:log_formatter] if @options[:log_formatter]
|
71
66
|
|
72
|
-
|
73
|
-
|
67
|
+
generate_restart_data
|
68
|
+
|
69
|
+
if clustered? && !Process.respond_to?(:fork)
|
70
|
+
unsupported "worker mode not supported on #{RUBY_ENGINE} on this platform"
|
74
71
|
end
|
75
72
|
|
76
|
-
|
77
|
-
Dir.chdir(dir) if dir
|
73
|
+
Dir.chdir(@restart_dir)
|
78
74
|
|
79
75
|
prune_bundler if prune_bundler?
|
80
76
|
|
@@ -82,18 +78,18 @@ module Puma
|
|
82
78
|
set_rack_environment
|
83
79
|
|
84
80
|
if clustered?
|
85
|
-
@events.formatter = Events::PidFormatter.new
|
86
81
|
@options[:logger] = @events
|
87
82
|
|
88
83
|
@runner = Cluster.new(self, @events)
|
89
84
|
else
|
90
85
|
@runner = Single.new(self, @events)
|
91
86
|
end
|
87
|
+
Puma.stats_object = @runner
|
92
88
|
|
93
89
|
@status = :run
|
94
90
|
end
|
95
91
|
|
96
|
-
attr_reader :binder, :events, :config, :options
|
92
|
+
attr_reader :binder, :events, :config, :options, :restart_dir
|
97
93
|
|
98
94
|
# Return stats about the server
|
99
95
|
def stats
|
@@ -106,14 +102,17 @@ module Puma
|
|
106
102
|
write_pid
|
107
103
|
|
108
104
|
path = @options[:state]
|
105
|
+
permission = @options[:state_permission]
|
109
106
|
return unless path
|
110
107
|
|
108
|
+
require 'puma/state_file'
|
109
|
+
|
111
110
|
sf = StateFile.new
|
112
111
|
sf.pid = Process.pid
|
113
112
|
sf.control_url = @options[:control_url]
|
114
113
|
sf.control_auth_token = @options[:control_auth_token]
|
115
114
|
|
116
|
-
sf.save path
|
115
|
+
sf.save path, permission
|
117
116
|
end
|
118
117
|
|
119
118
|
# Delete the configured pidfile
|
@@ -122,19 +121,6 @@ module Puma
|
|
122
121
|
File.unlink(path) if path && File.exist?(path)
|
123
122
|
end
|
124
123
|
|
125
|
-
# If configured, write the pid of the current process out
|
126
|
-
# to a file.
|
127
|
-
def write_pid
|
128
|
-
path = @options[:pidfile]
|
129
|
-
return unless path
|
130
|
-
|
131
|
-
File.open(path, 'w') { |f| f.puts Process.pid }
|
132
|
-
cur = Process.pid
|
133
|
-
at_exit do
|
134
|
-
delete_pidfile if cur == Process.pid
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
124
|
# Begin async shutdown of the server
|
139
125
|
def halt
|
140
126
|
@status = :halt
|
@@ -164,6 +150,17 @@ module Puma
|
|
164
150
|
|
165
151
|
# Run the server. This blocks until the server is stopped
|
166
152
|
def run
|
153
|
+
previous_env =
|
154
|
+
if defined?(Bundler)
|
155
|
+
env = Bundler::ORIGINAL_ENV.dup
|
156
|
+
# add -rbundler/setup so we load from Gemfile when restarting
|
157
|
+
bundle = "-rbundler/setup"
|
158
|
+
env["RUBYOPT"] = [env["RUBYOPT"], bundle].join(" ").lstrip unless env["RUBYOPT"].to_s.include?(bundle)
|
159
|
+
env
|
160
|
+
else
|
161
|
+
ENV.to_h
|
162
|
+
end
|
163
|
+
|
167
164
|
@config.clamp
|
168
165
|
|
169
166
|
@config.plugins.fire_starts self
|
@@ -179,26 +176,66 @@ module Puma
|
|
179
176
|
graceful_stop
|
180
177
|
when :restart
|
181
178
|
log "* Restarting..."
|
179
|
+
ENV.replace(previous_env)
|
182
180
|
@runner.before_restart
|
183
181
|
restart!
|
184
182
|
when :exit
|
185
183
|
# nothing
|
186
184
|
end
|
185
|
+
close_binder_listeners unless @status == :restart
|
187
186
|
end
|
188
187
|
|
189
|
-
# Return
|
190
|
-
def
|
191
|
-
@binder.
|
188
|
+
# Return all tcp ports the launcher may be using, TCP or SSL
|
189
|
+
def connected_ports
|
190
|
+
@binder.connected_ports
|
191
|
+
end
|
192
|
+
|
193
|
+
def restart_args
|
194
|
+
cmd = @options[:restart_cmd]
|
195
|
+
if cmd
|
196
|
+
cmd.split(' ') + @original_argv
|
197
|
+
else
|
198
|
+
@restart_argv
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def close_binder_listeners
|
203
|
+
@runner.close_control_listeners
|
204
|
+
@binder.close_listeners
|
205
|
+
end
|
206
|
+
|
207
|
+
def thread_status
|
208
|
+
Thread.list.each do |thread|
|
209
|
+
name = "Thread: TID-#{thread.object_id.to_s(36)}"
|
210
|
+
name += " #{thread['label']}" if thread['label']
|
211
|
+
name += " #{thread.name}" if thread.respond_to?(:name) && thread.name
|
212
|
+
backtrace = thread.backtrace || ["<no backtrace available>"]
|
213
|
+
|
214
|
+
yield name, backtrace
|
215
|
+
end
|
192
216
|
end
|
193
217
|
|
194
218
|
private
|
195
219
|
|
220
|
+
# If configured, write the pid of the current process out
|
221
|
+
# to a file.
|
222
|
+
def write_pid
|
223
|
+
path = @options[:pidfile]
|
224
|
+
return unless path
|
225
|
+
|
226
|
+
File.open(path, 'w') { |f| f.puts Process.pid }
|
227
|
+
cur = Process.pid
|
228
|
+
at_exit do
|
229
|
+
delete_pidfile if cur == Process.pid
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
196
233
|
def reload_worker_directory
|
197
234
|
@runner.reload_worker_directory if @runner.respond_to?(:reload_worker_directory)
|
198
235
|
end
|
199
236
|
|
200
237
|
def restart!
|
201
|
-
@config.run_hooks :on_restart, self
|
238
|
+
@config.run_hooks :on_restart, self, @events
|
202
239
|
|
203
240
|
if Puma.jruby?
|
204
241
|
close_binder_listeners
|
@@ -212,46 +249,74 @@ module Puma
|
|
212
249
|
Dir.chdir(@restart_dir)
|
213
250
|
Kernel.exec(*argv)
|
214
251
|
else
|
215
|
-
redirects = {:close_others => true}
|
216
|
-
@binder.listeners.each_with_index do |(l, io), i|
|
217
|
-
ENV["PUMA_INHERIT_#{i}"] = "#{io.to_i}:#{l}"
|
218
|
-
redirects[io.to_i] = io.to_i
|
219
|
-
end
|
220
|
-
|
221
252
|
argv = restart_args
|
222
253
|
Dir.chdir(@restart_dir)
|
223
|
-
|
254
|
+
ENV.update(@binder.redirects_for_restart_env)
|
255
|
+
argv += [@binder.redirects_for_restart]
|
224
256
|
Kernel.exec(*argv)
|
225
257
|
end
|
226
258
|
end
|
227
259
|
|
228
|
-
def
|
229
|
-
|
230
|
-
|
231
|
-
|
260
|
+
def dependencies_and_files_to_require_after_prune
|
261
|
+
puma = spec_for_gem("puma")
|
262
|
+
|
263
|
+
deps = puma.runtime_dependencies.map do |d|
|
264
|
+
"#{d.name}:#{spec_for_gem(d.name).version}"
|
265
|
+
end
|
266
|
+
|
267
|
+
[deps, require_paths_for_gem(puma) + extra_runtime_deps_directories]
|
268
|
+
end
|
269
|
+
|
270
|
+
def extra_runtime_deps_directories
|
271
|
+
Array(@options[:extra_runtime_dependencies]).map do |d_name|
|
272
|
+
if (spec = spec_for_gem(d_name))
|
273
|
+
require_paths_for_gem(spec)
|
274
|
+
else
|
275
|
+
log "* Could not load extra dependency: #{d_name}"
|
276
|
+
nil
|
277
|
+
end
|
278
|
+
end.flatten.compact
|
279
|
+
end
|
280
|
+
|
281
|
+
def puma_wild_location
|
282
|
+
puma = spec_for_gem("puma")
|
283
|
+
dirs = require_paths_for_gem(puma)
|
232
284
|
puma_lib_dir = dirs.detect { |x| File.exist? File.join(x, '../bin/puma-wild') }
|
285
|
+
File.expand_path(File.join(puma_lib_dir, "../bin/puma-wild"))
|
286
|
+
end
|
233
287
|
|
234
|
-
|
288
|
+
def prune_bundler
|
289
|
+
return unless defined?(Bundler)
|
290
|
+
require_rubygems_min_version!(Gem::Version.new("2.2"), "prune_bundler")
|
291
|
+
unless puma_wild_location
|
235
292
|
log "! Unable to prune Bundler environment, continuing"
|
236
293
|
return
|
237
294
|
end
|
238
295
|
|
239
|
-
deps =
|
240
|
-
spec = Bundler.rubygems.loaded_specs(d.name)
|
241
|
-
"#{d.name}:#{spec.version.to_s}"
|
242
|
-
end
|
296
|
+
deps, dirs = dependencies_and_files_to_require_after_prune
|
243
297
|
|
244
298
|
log '* Pruning Bundler environment'
|
245
299
|
home = ENV['GEM_HOME']
|
246
|
-
Bundler.
|
300
|
+
bundle_gemfile = Bundler.original_env['BUNDLE_GEMFILE']
|
301
|
+
with_unbundled_env do
|
247
302
|
ENV['GEM_HOME'] = home
|
303
|
+
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
248
304
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
249
|
-
|
250
|
-
|
305
|
+
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':'), deps.join(',')] + @original_argv
|
306
|
+
# Ruby 2.0+ defaults to true which breaks socket activation
|
307
|
+
args += [{:close_others => false}]
|
251
308
|
Kernel.exec(*args)
|
252
309
|
end
|
253
310
|
end
|
254
311
|
|
312
|
+
def spec_for_gem(gem_name)
|
313
|
+
Bundler.rubygems.loaded_specs(gem_name)
|
314
|
+
end
|
315
|
+
|
316
|
+
def require_paths_for_gem(gem_spec)
|
317
|
+
gem_spec.full_require_paths
|
318
|
+
end
|
319
|
+
|
255
320
|
def log(str)
|
256
321
|
@events.log str
|
257
322
|
end
|
@@ -260,15 +325,6 @@ module Puma
|
|
260
325
|
(@options[:workers] || 0) > 0
|
261
326
|
end
|
262
327
|
|
263
|
-
def restart_args
|
264
|
-
cmd = @options[:restart_cmd]
|
265
|
-
if cmd
|
266
|
-
cmd.split(' ') + @original_argv
|
267
|
-
else
|
268
|
-
@restart_argv
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
328
|
def unsupported(str)
|
273
329
|
@events.error(str)
|
274
330
|
raise UnsupportedOption
|
@@ -285,8 +341,8 @@ module Puma
|
|
285
341
|
end
|
286
342
|
|
287
343
|
def title
|
288
|
-
buffer
|
289
|
-
buffer
|
344
|
+
buffer = "puma #{Puma::Const::VERSION} (#{@options[:binds].join(',')})"
|
345
|
+
buffer += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
290
346
|
buffer
|
291
347
|
end
|
292
348
|
|
@@ -303,34 +359,29 @@ module Puma
|
|
303
359
|
@options[:prune_bundler] && clustered? && !@options[:preload_app]
|
304
360
|
end
|
305
361
|
|
306
|
-
def close_binder_listeners
|
307
|
-
@binder.listeners.each do |l, io|
|
308
|
-
io.close
|
309
|
-
uri = URI.parse(l)
|
310
|
-
next unless uri.scheme == 'unix'
|
311
|
-
File.unlink("#{uri.host}#{uri.path}")
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
|
316
362
|
def generate_restart_data
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
363
|
+
if dir = @options[:directory]
|
364
|
+
@restart_dir = dir
|
365
|
+
|
366
|
+
elsif Puma.windows?
|
367
|
+
# I guess the value of PWD is garbage on windows so don't bother
|
368
|
+
# using it.
|
369
|
+
@restart_dir = Dir.pwd
|
370
|
+
|
371
|
+
# Use the same trick as unicorn, namely favor PWD because
|
372
|
+
# it will contain an unresolved symlink, useful for when
|
373
|
+
# the pwd is /data/releases/current.
|
374
|
+
elsif dir = ENV['PWD']
|
321
375
|
s_env = File.stat(dir)
|
322
376
|
s_pwd = File.stat(Dir.pwd)
|
323
377
|
|
324
378
|
if s_env.ino == s_pwd.ino and (Puma.jruby? or s_env.dev == s_pwd.dev)
|
325
379
|
@restart_dir = dir
|
326
|
-
@config.configure { |c| c.worker_directory dir }
|
327
380
|
end
|
328
381
|
end
|
329
382
|
|
330
383
|
@restart_dir ||= Dir.pwd
|
331
384
|
|
332
|
-
require 'rubygems'
|
333
|
-
|
334
385
|
# if $0 is a file in the current directory, then restart
|
335
386
|
# it the same, otherwise add -S on there because it was
|
336
387
|
# picked up in PATH.
|
@@ -341,9 +392,10 @@ module Puma
|
|
341
392
|
arg0 = [Gem.ruby, "-S", $0]
|
342
393
|
end
|
343
394
|
|
344
|
-
# Detect and reinject -Ilib from the command line
|
395
|
+
# Detect and reinject -Ilib from the command line, used for testing without bundler
|
396
|
+
# cruby has an expanded path, jruby has just "lib"
|
345
397
|
lib = File.expand_path "lib"
|
346
|
-
arg0[1,0] = ["-I", lib] if
|
398
|
+
arg0[1,0] = ["-I", lib] if [lib, "lib"].include?($LOAD_PATH[0])
|
347
399
|
|
348
400
|
if defined? Puma::WILD_ARGS
|
349
401
|
@restart_argv = arg0 + Puma::WILD_ARGS + @original_argv
|
@@ -361,36 +413,74 @@ module Puma
|
|
361
413
|
log "*** SIGUSR2 not implemented, signal based restart unavailable!"
|
362
414
|
end
|
363
415
|
|
416
|
+
unless Puma.jruby?
|
417
|
+
begin
|
418
|
+
Signal.trap "SIGUSR1" do
|
419
|
+
phased_restart
|
420
|
+
end
|
421
|
+
rescue Exception
|
422
|
+
log "*** SIGUSR1 not implemented, signal based restart unavailable!"
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
364
426
|
begin
|
365
|
-
Signal.trap "
|
366
|
-
|
427
|
+
Signal.trap "SIGTERM" do
|
428
|
+
graceful_stop
|
429
|
+
|
430
|
+
raise(SignalException, "SIGTERM") if @options[:raise_exception_on_sigterm]
|
367
431
|
end
|
368
432
|
rescue Exception
|
369
|
-
log "***
|
433
|
+
log "*** SIGTERM not implemented, signal based gracefully stopping unavailable!"
|
370
434
|
end
|
371
435
|
|
372
436
|
begin
|
373
|
-
Signal.trap "
|
437
|
+
Signal.trap "SIGINT" do
|
374
438
|
stop
|
375
439
|
end
|
376
440
|
rescue Exception
|
377
|
-
log "***
|
441
|
+
log "*** SIGINT not implemented, signal based gracefully stopping unavailable!"
|
378
442
|
end
|
379
443
|
|
380
444
|
begin
|
381
445
|
Signal.trap "SIGHUP" do
|
382
|
-
@runner.
|
446
|
+
if @runner.redirected_io?
|
447
|
+
@runner.redirect_io
|
448
|
+
else
|
449
|
+
stop
|
450
|
+
end
|
383
451
|
end
|
384
452
|
rescue Exception
|
385
453
|
log "*** SIGHUP not implemented, signal based logs reopening unavailable!"
|
386
454
|
end
|
387
455
|
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
456
|
+
begin
|
457
|
+
unless Puma.jruby? # INFO in use by JVM already
|
458
|
+
Signal.trap "SIGINFO" do
|
459
|
+
thread_status do |name, backtrace|
|
460
|
+
@events.log name
|
461
|
+
@events.log backtrace.map { |bt| " #{bt}" }
|
462
|
+
end
|
463
|
+
end
|
393
464
|
end
|
465
|
+
rescue Exception
|
466
|
+
# Not going to log this one, as SIGINFO is *BSD only and would be pretty annoying
|
467
|
+
# to see this constantly on Linux.
|
468
|
+
end
|
469
|
+
end
|
470
|
+
|
471
|
+
def require_rubygems_min_version!(min_version, feature)
|
472
|
+
return if min_version <= Gem::Version.new(Gem::VERSION)
|
473
|
+
|
474
|
+
raise "#{feature} is not supported on your version of RubyGems. " \
|
475
|
+
"You must have RubyGems #{min_version}+ to use this feature."
|
476
|
+
end
|
477
|
+
|
478
|
+
def with_unbundled_env
|
479
|
+
bundler_ver = Gem::Version.new(Bundler::VERSION)
|
480
|
+
if bundler_ver < Gem::Version.new('2.1.0')
|
481
|
+
Bundler.with_clean_env { yield }
|
482
|
+
else
|
483
|
+
Bundler.with_unbundled_env { yield }
|
394
484
|
end
|
395
485
|
end
|
396
486
|
end
|