puma 2.16.0 → 3.0.0.rc1
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/Manifest.txt +5 -0
- data/README.md +4 -1
- data/ext/puma_http11/http11_parser.java.rl +5 -5
- data/ext/puma_http11/org/jruby/puma/Http11Parser.java +39 -39
- data/lib/puma.rb +1 -0
- data/lib/puma/app/status.rb +1 -1
- data/lib/puma/binder.rb +6 -1
- data/lib/puma/cli.rb +125 -494
- data/lib/puma/cluster.rb +21 -18
- data/lib/puma/configuration.rb +189 -58
- data/lib/puma/const.rb +2 -2
- data/lib/puma/control_cli.rb +57 -72
- data/lib/puma/convenient.rb +23 -0
- data/lib/puma/daemon_ext.rb +6 -0
- data/lib/puma/detect.rb +8 -1
- data/lib/puma/dsl.rb +105 -26
- data/lib/puma/events.rb +5 -0
- data/lib/puma/launcher.rb +397 -0
- data/lib/puma/null_io.rb +15 -0
- data/lib/puma/plugin.rb +91 -0
- data/lib/puma/plugin/tmp_restart.rb +23 -0
- data/lib/puma/runner.rb +19 -14
- data/lib/puma/server.rb +1 -0
- data/lib/puma/single.rb +9 -4
- data/lib/puma/state_file.rb +27 -0
- data/lib/rack/handler/puma.rb +26 -27
- metadata +9 -4
data/lib/puma/control_cli.rb
CHANGED
@@ -9,12 +9,17 @@ module Puma
|
|
9
9
|
|
10
10
|
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory}
|
11
11
|
|
12
|
-
def is_windows?
|
13
|
-
RUBY_PLATFORM =~ /(win|w)32$/ ? true : false
|
14
|
-
end
|
15
|
-
|
16
12
|
def initialize(argv, stdout=STDOUT, stderr=STDERR)
|
17
|
-
@
|
13
|
+
@state = nil
|
14
|
+
@quiet = false
|
15
|
+
@pidfile = nil
|
16
|
+
@pid = nil
|
17
|
+
@control_url = nil
|
18
|
+
@control_auth_token = nil
|
19
|
+
@config_file = nil
|
20
|
+
@command = nil
|
21
|
+
|
22
|
+
@argv = argv.dup
|
18
23
|
@stdout = stdout
|
19
24
|
@stderr = stderr
|
20
25
|
@cli_options = {}
|
@@ -23,31 +28,31 @@ module Puma
|
|
23
28
|
o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{COMMANDS.join("|")})"
|
24
29
|
|
25
30
|
o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
|
26
|
-
@
|
31
|
+
@state = arg
|
27
32
|
end
|
28
33
|
|
29
34
|
o.on "-Q", "--quiet", "Not display messages" do |arg|
|
30
|
-
@
|
35
|
+
@quiet = true
|
31
36
|
end
|
32
37
|
|
33
38
|
o.on "-P", "--pidfile PATH", "Pid file" do |arg|
|
34
|
-
@
|
39
|
+
@pidfile = arg
|
35
40
|
end
|
36
41
|
|
37
42
|
o.on "-p", "--pid PID", "Pid" do |arg|
|
38
|
-
@
|
43
|
+
@pid = arg.to_i
|
39
44
|
end
|
40
45
|
|
41
46
|
o.on "-C", "--control-url URL", "The bind url to use for the control server" do |arg|
|
42
|
-
@
|
47
|
+
@control_url = arg
|
43
48
|
end
|
44
49
|
|
45
50
|
o.on "-T", "--control-token TOKEN", "The token to use as authentication for the control server" do |arg|
|
46
|
-
@
|
51
|
+
@control_auth_token = arg
|
47
52
|
end
|
48
53
|
|
49
54
|
o.on "-F", "--config-file PATH", "Puma config script" do |arg|
|
50
|
-
@
|
55
|
+
@config_file = arg
|
51
56
|
end
|
52
57
|
|
53
58
|
o.on_tail("-H", "--help", "Show this message") do
|
@@ -63,32 +68,29 @@ module Puma
|
|
63
68
|
|
64
69
|
opts.order!(argv) { |a| opts.terminate a }
|
65
70
|
|
66
|
-
command = argv.shift
|
67
|
-
@cli_options[:command] = command if command
|
68
|
-
|
69
|
-
@options = nil
|
71
|
+
@command = argv.shift
|
70
72
|
|
71
|
-
unless @
|
72
|
-
if @
|
73
|
-
@
|
73
|
+
unless @config_file == '-'
|
74
|
+
if @config_file.nil? and File.exist?('config/puma.rb')
|
75
|
+
@config_file = 'config/puma.rb'
|
74
76
|
end
|
75
77
|
|
76
|
-
if @
|
77
|
-
config = Puma::Configuration.
|
78
|
-
config.
|
79
|
-
@
|
78
|
+
if @config_file
|
79
|
+
config = Puma::Configuration.from_file @config_file
|
80
|
+
@state ||= config.options[:state]
|
81
|
+
@control_url ||= config.options[:control_url]
|
82
|
+
@control_auth_token ||= config.options[:control_auth_token]
|
83
|
+
@pidfile ||= config.options[:pidfile]
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
83
|
-
@options ||= @cli_options
|
84
|
-
|
85
87
|
# check present of command
|
86
|
-
unless @
|
88
|
+
unless @command
|
87
89
|
raise "Available commands: #{COMMANDS.join(", ")}"
|
88
90
|
end
|
89
91
|
|
90
|
-
unless COMMANDS.include? @
|
91
|
-
raise "Invalid command: #{@
|
92
|
+
unless COMMANDS.include? @command
|
93
|
+
raise "Invalid command: #{@command}"
|
92
94
|
end
|
93
95
|
|
94
96
|
rescue => e
|
@@ -97,45 +99,29 @@ module Puma
|
|
97
99
|
end
|
98
100
|
|
99
101
|
def message(msg)
|
100
|
-
@stdout.puts msg unless @
|
102
|
+
@stdout.puts msg unless @quiet
|
101
103
|
end
|
102
104
|
|
103
105
|
def prepare_configuration
|
104
|
-
if @
|
105
|
-
unless File.exist? @
|
106
|
-
raise "
|
106
|
+
if @state
|
107
|
+
unless File.exist? @state
|
108
|
+
raise "State file not found: #{@state}"
|
107
109
|
end
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
if status.kind_of?(Hash) && status.has_key?("config")
|
112
|
-
|
113
|
-
conf = status["config"]
|
114
|
-
|
115
|
-
# get control_url
|
116
|
-
if url = conf.options[:control_url]
|
117
|
-
@options[:control_url] = url
|
118
|
-
end
|
119
|
-
|
120
|
-
# get control_auth_token
|
121
|
-
if token = conf.options[:control_auth_token]
|
122
|
-
@options[:control_auth_token] = token
|
123
|
-
end
|
124
|
-
|
125
|
-
# get pid
|
126
|
-
@options[:pid] = status["pid"].to_i
|
127
|
-
else
|
128
|
-
raise "Invalid status file: #{@options[:state]}"
|
129
|
-
end
|
111
|
+
sf = StateFile.new
|
112
|
+
sf.load @state
|
130
113
|
|
131
|
-
|
114
|
+
@control_url = sf.control_url
|
115
|
+
@control_auth_token = sf.control_auth_token
|
116
|
+
@pid = sf.pid
|
117
|
+
elsif @pidfile
|
132
118
|
# get pid from pid_file
|
133
|
-
@
|
119
|
+
@pid = File.open(@pidfile).gets.to_i
|
134
120
|
end
|
135
121
|
end
|
136
122
|
|
137
123
|
def send_request
|
138
|
-
uri = URI.parse @
|
124
|
+
uri = URI.parse @control_url
|
139
125
|
|
140
126
|
# create server object by scheme
|
141
127
|
@server = case uri.scheme
|
@@ -147,13 +133,13 @@ module Puma
|
|
147
133
|
raise "Invalid scheme: #{uri.scheme}"
|
148
134
|
end
|
149
135
|
|
150
|
-
if @
|
136
|
+
if @command == "status"
|
151
137
|
message "Puma is started"
|
152
138
|
else
|
153
|
-
url = "/#{@
|
139
|
+
url = "/#{@command}"
|
154
140
|
|
155
|
-
if @
|
156
|
-
url = url + "?token=#{@
|
141
|
+
if @control_auth_token
|
142
|
+
url = url + "?token=#{@control_auth_token}"
|
157
143
|
end
|
158
144
|
|
159
145
|
@server << "GET #{url} HTTP/1.0\r\n\r\n"
|
@@ -178,30 +164,29 @@ module Puma
|
|
178
164
|
raise "Bad response from server: #{@code}"
|
179
165
|
end
|
180
166
|
|
181
|
-
message "Command #{@
|
182
|
-
message response.last if @
|
167
|
+
message "Command #{@command} sent success"
|
168
|
+
message response.last if @command == "stats"
|
183
169
|
end
|
184
170
|
|
185
171
|
@server.close
|
186
172
|
end
|
187
173
|
|
188
174
|
def send_signal
|
189
|
-
unless
|
175
|
+
unless @pid
|
190
176
|
raise "Neither pid nor control url available"
|
191
177
|
end
|
192
178
|
|
193
179
|
begin
|
194
180
|
Process.getpgid pid
|
195
181
|
rescue SystemCallError
|
196
|
-
if @
|
197
|
-
@options.delete(:command)
|
182
|
+
if @command == "restart"
|
198
183
|
start
|
199
184
|
else
|
200
185
|
raise "No pid '#{pid}' found"
|
201
186
|
end
|
202
187
|
end
|
203
188
|
|
204
|
-
case @
|
189
|
+
case @command
|
205
190
|
when "restart"
|
206
191
|
Process.kill "SIGUSR2", pid
|
207
192
|
|
@@ -227,18 +212,18 @@ module Puma
|
|
227
212
|
return
|
228
213
|
end
|
229
214
|
|
230
|
-
message "Command #{@
|
215
|
+
message "Command #{@command} sent success"
|
231
216
|
end
|
232
217
|
|
233
218
|
def run
|
234
|
-
start if @
|
219
|
+
start if @command == "start"
|
235
220
|
|
236
221
|
prepare_configuration
|
237
222
|
|
238
|
-
if
|
223
|
+
if Puma.windows?
|
239
224
|
send_request
|
240
225
|
else
|
241
|
-
@
|
226
|
+
@control_url ? send_request : send_signal
|
242
227
|
end
|
243
228
|
|
244
229
|
rescue => e
|
@@ -252,11 +237,11 @@ module Puma
|
|
252
237
|
|
253
238
|
run_args = @argv
|
254
239
|
|
255
|
-
if path = @
|
240
|
+
if path = @state
|
256
241
|
run_args = ["-S", path] + run_args
|
257
242
|
end
|
258
243
|
|
259
|
-
if path = @
|
244
|
+
if path = @config_file
|
260
245
|
run_args = ["-C", path] + run_args
|
261
246
|
end
|
262
247
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'puma/launcher'
|
2
|
+
require 'puma/configuration'
|
3
|
+
|
4
|
+
module Puma
|
5
|
+
def self.run(opts={})
|
6
|
+
cfg = Puma::Configuration.new do |c|
|
7
|
+
if port = opts[:port]
|
8
|
+
c.port port
|
9
|
+
end
|
10
|
+
|
11
|
+
c.quiet
|
12
|
+
|
13
|
+
yield c
|
14
|
+
end
|
15
|
+
|
16
|
+
cfg.clamp
|
17
|
+
|
18
|
+
events = Puma::Events.null
|
19
|
+
|
20
|
+
launcher = Puma::Launcher.new cfg, :events => events
|
21
|
+
launcher.run
|
22
|
+
end
|
23
|
+
end
|
data/lib/puma/daemon_ext.rb
CHANGED
@@ -3,6 +3,12 @@ module Process
|
|
3
3
|
# This overrides the default version because it is broken if it
|
4
4
|
# exists.
|
5
5
|
|
6
|
+
if respond_to? :daemon
|
7
|
+
class << self
|
8
|
+
remove_method :daemon
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
6
12
|
def self.daemon(nochdir=false, noclose=false)
|
7
13
|
exit if fork # Parent exits, child continues.
|
8
14
|
|
data/lib/puma/detect.rb
CHANGED
data/lib/puma/dsl.rb
CHANGED
@@ -4,20 +4,57 @@ module Puma
|
|
4
4
|
class DSL
|
5
5
|
include ConfigDefault
|
6
6
|
|
7
|
-
def self.load(options, path)
|
8
|
-
new(options)
|
9
|
-
|
10
|
-
end
|
7
|
+
def self.load(options, cfg, path)
|
8
|
+
d = new(options, cfg)
|
9
|
+
d._load_from(path)
|
11
10
|
|
12
11
|
options
|
12
|
+
ensure
|
13
|
+
d._offer_plugins
|
13
14
|
end
|
14
15
|
|
15
|
-
def initialize(options)
|
16
|
+
def initialize(options, config)
|
17
|
+
@config = config
|
16
18
|
@options = options
|
19
|
+
|
20
|
+
@plugins = []
|
17
21
|
end
|
18
22
|
|
19
23
|
def _load_from(path)
|
20
24
|
instance_eval(File.read(path), path, 1) if path
|
25
|
+
ensure
|
26
|
+
_offer_plugins
|
27
|
+
end
|
28
|
+
|
29
|
+
def _offer_plugins
|
30
|
+
@plugins.each do |o|
|
31
|
+
if o.respond_to? :config
|
32
|
+
@options.shift
|
33
|
+
o.config self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@plugins.clear
|
38
|
+
end
|
39
|
+
|
40
|
+
def _run(&blk)
|
41
|
+
blk.call self
|
42
|
+
ensure
|
43
|
+
_offer_plugins
|
44
|
+
end
|
45
|
+
|
46
|
+
def inject(&blk)
|
47
|
+
instance_eval(&blk)
|
48
|
+
end
|
49
|
+
|
50
|
+
def get(key,default=nil)
|
51
|
+
@options[key.to_sym] || default
|
52
|
+
end
|
53
|
+
|
54
|
+
# Load the named plugin for use by this configuration
|
55
|
+
#
|
56
|
+
def plugin(name)
|
57
|
+
@plugins << @config.load_plugin(name)
|
21
58
|
end
|
22
59
|
|
23
60
|
# Use +obj+ or +block+ as the Rack app. This allows a config file to
|
@@ -34,29 +71,43 @@ module Puma
|
|
34
71
|
# Start the Puma control rack app on +url+. This app can be communicated
|
35
72
|
# with to control the main server.
|
36
73
|
#
|
37
|
-
def activate_control_app(url="auto", opts=
|
38
|
-
|
74
|
+
def activate_control_app(url="auto", opts={})
|
75
|
+
if url == "auto"
|
76
|
+
path = Configuration.temp_path
|
77
|
+
@options[:control_url] = "unix://#{path}"
|
78
|
+
@options[:control_url_temp] = path
|
79
|
+
else
|
80
|
+
@options[:control_url] = url
|
81
|
+
end
|
39
82
|
|
40
|
-
if opts
|
83
|
+
if opts[:no_token]
|
84
|
+
auth_token = :none
|
85
|
+
else
|
41
86
|
auth_token = opts[:auth_token]
|
42
|
-
|
43
|
-
|
44
|
-
@options[:control_auth_token] = :none if opts[:no_token]
|
45
|
-
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
87
|
+
auth_token ||= Configuration.random_token
|
46
88
|
end
|
89
|
+
|
90
|
+
@options[:control_auth_token] = auth_token
|
91
|
+
@options[:control_url_umask] = opts[:umask] if opts[:umask]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Load additional configuration from a file
|
95
|
+
def load(file)
|
96
|
+
_ary(:config_files) << file
|
47
97
|
end
|
48
98
|
|
49
99
|
# Bind the server to +url+. tcp:// and unix:// are the only accepted
|
50
100
|
# protocols.
|
51
101
|
#
|
52
102
|
def bind(url)
|
53
|
-
|
103
|
+
_ary(:binds) << url
|
54
104
|
end
|
55
105
|
|
56
106
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
57
107
|
#
|
58
|
-
def port(port)
|
59
|
-
|
108
|
+
def port(port, host=nil)
|
109
|
+
host ||= Configuration::DefaultTCPHost
|
110
|
+
bind "tcp://#{host}:#{port}"
|
60
111
|
end
|
61
112
|
|
62
113
|
# Work around leaky apps that leave garbage in Thread locals
|
@@ -91,7 +142,7 @@ module Puma
|
|
91
142
|
# This can be called multiple times to add code each time.
|
92
143
|
#
|
93
144
|
def on_restart(&block)
|
94
|
-
|
145
|
+
_ary(:on_restart) << block
|
95
146
|
end
|
96
147
|
|
97
148
|
# Command to use to restart puma. This should be just how to
|
@@ -99,12 +150,12 @@ module Puma
|
|
99
150
|
# to puma, as those are the same as the original process.
|
100
151
|
#
|
101
152
|
def restart_command(cmd)
|
102
|
-
@options[:restart_cmd] = cmd
|
153
|
+
@options[:restart_cmd] = cmd.to_s
|
103
154
|
end
|
104
155
|
|
105
156
|
# Store the pid of the server in the file at +path+.
|
106
157
|
def pidfile(path)
|
107
|
-
@options[:pidfile] = path
|
158
|
+
@options[:pidfile] = path.to_s
|
108
159
|
end
|
109
160
|
|
110
161
|
# Disable request logging.
|
@@ -113,12 +164,24 @@ module Puma
|
|
113
164
|
@options[:quiet] = true
|
114
165
|
end
|
115
166
|
|
167
|
+
# Show debugging info
|
168
|
+
#
|
169
|
+
def debug
|
170
|
+
@options[:debug] = true
|
171
|
+
end
|
172
|
+
|
116
173
|
# Load +path+ as a rackup file.
|
117
174
|
#
|
118
175
|
def rackup(path)
|
119
176
|
@options[:rackup] = path.to_s
|
120
177
|
end
|
121
178
|
|
179
|
+
# Run Puma in TCP mode
|
180
|
+
#
|
181
|
+
def tcp_mode!
|
182
|
+
@options[:mode] = :tcp
|
183
|
+
end
|
184
|
+
|
122
185
|
# Redirect STDOUT and STDERR to files specified.
|
123
186
|
def stdout_redirect(stdout=nil, stderr=nil, append=false)
|
124
187
|
@options[:redirect_stdout] = stdout
|
@@ -136,6 +199,10 @@ module Puma
|
|
136
199
|
raise "The minimum (#{min}) number of threads must be less than or equal to the max (#{max})"
|
137
200
|
end
|
138
201
|
|
202
|
+
if max < 1
|
203
|
+
raise "The maximum number of threads (#{max}) must be greater than 0"
|
204
|
+
end
|
205
|
+
|
139
206
|
@options[:min_threads] = min
|
140
207
|
@options[:max_threads] = max
|
141
208
|
end
|
@@ -143,9 +210,9 @@ module Puma
|
|
143
210
|
def ssl_bind(host, port, opts)
|
144
211
|
if defined?(JRUBY_VERSION)
|
145
212
|
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
146
|
-
|
213
|
+
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
|
147
214
|
else
|
148
|
-
|
215
|
+
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
|
149
216
|
end
|
150
217
|
end
|
151
218
|
|
@@ -172,7 +239,7 @@ module Puma
|
|
172
239
|
# This can be called multiple times to add hooks.
|
173
240
|
#
|
174
241
|
def before_fork(&block)
|
175
|
-
|
242
|
+
_ary(:before_fork) << block
|
176
243
|
end
|
177
244
|
|
178
245
|
# *Cluster mode only* Code to run immediately before a worker shuts
|
@@ -183,7 +250,7 @@ module Puma
|
|
183
250
|
# This can be called multiple times to add hooks.
|
184
251
|
#
|
185
252
|
def on_worker_shutdown(&block)
|
186
|
-
|
253
|
+
_ary(:before_worker_shutdown) << block
|
187
254
|
end
|
188
255
|
|
189
256
|
# *Cluster mode only* Code to run when a worker boots to setup
|
@@ -192,7 +259,7 @@ module Puma
|
|
192
259
|
# This can be called multiple times to add hooks.
|
193
260
|
#
|
194
261
|
def on_worker_boot(&block)
|
195
|
-
|
262
|
+
_ary(:before_worker_boot) << block
|
196
263
|
end
|
197
264
|
|
198
265
|
# *Cluster mode only* Code to run when a master process is
|
@@ -201,7 +268,7 @@ module Puma
|
|
201
268
|
# This can be called multiple times to add hooks.
|
202
269
|
#
|
203
270
|
def on_worker_fork(&block)
|
204
|
-
|
271
|
+
_ary(:before_worker_fork) << block
|
205
272
|
end
|
206
273
|
|
207
274
|
# *Cluster mode only* Code to run when a worker boots to setup
|
@@ -210,12 +277,18 @@ module Puma
|
|
210
277
|
# This can be called multiple times to add hooks.
|
211
278
|
#
|
212
279
|
def after_worker_boot(&block)
|
213
|
-
|
280
|
+
_ary(:after_worker_fork) << block
|
214
281
|
end
|
215
282
|
|
216
283
|
# The directory to operate out of.
|
217
284
|
def directory(dir)
|
218
285
|
@options[:directory] = dir.to_s
|
286
|
+
|
287
|
+
worker_directory dir
|
288
|
+
end
|
289
|
+
|
290
|
+
# Set the directory for workers to start in
|
291
|
+
def worker_directory(dir)
|
219
292
|
@options[:worker_directory] = dir.to_s
|
220
293
|
end
|
221
294
|
|
@@ -259,7 +332,7 @@ module Puma
|
|
259
332
|
|
260
333
|
# Additional text to display in process listing
|
261
334
|
def tag(string)
|
262
|
-
@options[:tag] = string
|
335
|
+
@options[:tag] = string.to_s
|
263
336
|
end
|
264
337
|
|
265
338
|
# *Cluster mode only* Set the timeout for workers in seconds
|
@@ -344,5 +417,11 @@ module Puma
|
|
344
417
|
raise "Invalid value for set_remote_address - #{val}"
|
345
418
|
end
|
346
419
|
end
|
420
|
+
|
421
|
+
private
|
422
|
+
|
423
|
+
def _ary(key)
|
424
|
+
(@options.cur[key] ||= [])
|
425
|
+
end
|
347
426
|
end
|
348
427
|
end
|