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.

@@ -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
- @argv = argv
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
- @cli_options[:state] = arg
31
+ @state = arg
27
32
  end
28
33
 
29
34
  o.on "-Q", "--quiet", "Not display messages" do |arg|
30
- @cli_options[:quiet_flag] = true
35
+ @quiet = true
31
36
  end
32
37
 
33
38
  o.on "-P", "--pidfile PATH", "Pid file" do |arg|
34
- @cli_options[:pidfile] = arg
39
+ @pidfile = arg
35
40
  end
36
41
 
37
42
  o.on "-p", "--pid PID", "Pid" do |arg|
38
- @cli_options[:pid] = arg.to_i
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
- @cli_options[:control_url] = arg
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
- @cli_options[:control_auth_token] = arg
51
+ @control_auth_token = arg
47
52
  end
48
53
 
49
54
  o.on "-F", "--config-file PATH", "Puma config script" do |arg|
50
- @cli_options[:config_file] = arg
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 @cli_options[:config_file] == '-'
72
- if @cli_options[:config_file].nil? and File.exist?('config/puma.rb')
73
- @cli_options[:config_file] = 'config/puma.rb'
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 @cli_options[:config_file]
77
- config = Puma::Configuration.new(@cli_options)
78
- config.load
79
- @options = config.options
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 @options[:command]
88
+ unless @command
87
89
  raise "Available commands: #{COMMANDS.join(", ")}"
88
90
  end
89
91
 
90
- unless COMMANDS.include? @options[:command]
91
- raise "Invalid command: #{@options[: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 @options[:quiet_flag]
102
+ @stdout.puts msg unless @quiet
101
103
  end
102
104
 
103
105
  def prepare_configuration
104
- if @options.has_key? :state
105
- unless File.exist? @options[:state]
106
- raise "Status file not found: #{@options[:state]}"
106
+ if @state
107
+ unless File.exist? @state
108
+ raise "State file not found: #{@state}"
107
109
  end
108
110
 
109
- status = YAML.load File.read(@options[:state])
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
- elsif @options.has_key? :pidfile
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
- @options[:pid] = File.open(@options[:pidfile]).gets.to_i
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 @options[:control_url]
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 @options[:command] == "status"
136
+ if @command == "status"
151
137
  message "Puma is started"
152
138
  else
153
- url = "/#{@options[:command]}"
139
+ url = "/#{@command}"
154
140
 
155
- if @options.has_key?(:control_auth_token)
156
- url = url + "?token=#{@options[:control_auth_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 #{@options[:command]} sent success"
182
- message response.last if @options[:command] == "stats"
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 pid = @options[:pid]
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 @options[:command] == "restart"
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 @options[:command]
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 #{@options[:command]} sent success"
215
+ message "Command #{@command} sent success"
231
216
  end
232
217
 
233
218
  def run
234
- start if @options[:command] == "start"
219
+ start if @command == "start"
235
220
 
236
221
  prepare_configuration
237
222
 
238
- if is_windows?
223
+ if Puma.windows?
239
224
  send_request
240
225
  else
241
- @options.has_key?(:control_url) ? send_request : send_signal
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 = @options[:state]
240
+ if path = @state
256
241
  run_args = ["-S", path] + run_args
257
242
  end
258
243
 
259
- if path = @options[:config_file]
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
@@ -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
 
@@ -1,4 +1,11 @@
1
1
  module Puma
2
2
  IS_JRUBY = defined?(JRUBY_VERSION)
3
- end
4
3
 
4
+ def self.jruby?
5
+ IS_JRUBY
6
+ end
7
+
8
+ def self.windows?
9
+ RUBY_PLATFORM =~ /mswin32|ming32/
10
+ end
11
+ end
@@ -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).tap do |obj|
9
- obj._load_from(path)
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=nil)
38
- @options[:control_url] = url
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
- @options[:control_auth_token] = auth_token if auth_token
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
- @options[:binds] << url
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
- @options[:binds] << "tcp://#{Configuration::DefaultTCPHost}:#{port}"
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
- @options[:on_restart] << block
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
- @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
213
+ bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}"
147
214
  else
148
- @options[:binds] << "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}"
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
- @options[:before_fork] << block
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
- @options[:before_worker_shutdown] << block
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
- @options[:before_worker_boot] << block
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
- @options[:before_worker_fork] << block
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
- @options[:after_worker_boot] << block
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