puma 3.4.0 → 3.12.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.

Files changed (71) hide show
  1. checksums.yaml +5 -5
  2. data/{History.txt → History.md} +356 -74
  3. data/README.md +143 -227
  4. data/docs/architecture.md +36 -0
  5. data/{DEPLOYMENT.md → docs/deployment.md} +1 -1
  6. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  7. data/docs/images/puma-connection-flow.png +0 -0
  8. data/docs/images/puma-general-arch.png +0 -0
  9. data/docs/plugins.md +28 -0
  10. data/docs/restart.md +39 -0
  11. data/docs/signals.md +56 -3
  12. data/docs/systemd.md +124 -22
  13. data/ext/puma_http11/extconf.rb +2 -0
  14. data/ext/puma_http11/http11_parser.c +291 -447
  15. data/ext/puma_http11/http11_parser.h +1 -0
  16. data/ext/puma_http11/http11_parser.rl +10 -9
  17. data/ext/puma_http11/http11_parser_common.rl +1 -1
  18. data/ext/puma_http11/io_buffer.c +7 -7
  19. data/ext/puma_http11/mini_ssl.c +67 -6
  20. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +76 -94
  21. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +15 -2
  22. data/ext/puma_http11/puma_http11.c +1 -0
  23. data/lib/puma.rb +13 -5
  24. data/lib/puma/app/status.rb +8 -0
  25. data/lib/puma/binder.rb +46 -21
  26. data/lib/puma/cli.rb +49 -33
  27. data/lib/puma/client.rb +149 -4
  28. data/lib/puma/cluster.rb +55 -13
  29. data/lib/puma/commonlogger.rb +19 -20
  30. data/lib/puma/compat.rb +3 -7
  31. data/lib/puma/configuration.rb +136 -131
  32. data/lib/puma/const.rb +19 -37
  33. data/lib/puma/control_cli.rb +38 -35
  34. data/lib/puma/convenient.rb +3 -3
  35. data/lib/puma/detect.rb +3 -1
  36. data/lib/puma/dsl.rb +86 -57
  37. data/lib/puma/events.rb +17 -13
  38. data/lib/puma/io_buffer.rb +1 -1
  39. data/lib/puma/jruby_restart.rb +0 -1
  40. data/lib/puma/launcher.rb +61 -30
  41. data/lib/puma/minissl.rb +85 -4
  42. data/lib/puma/null_io.rb +6 -13
  43. data/lib/puma/plugin.rb +12 -1
  44. data/lib/puma/plugin/tmp_restart.rb +1 -2
  45. data/lib/puma/rack/builder.rb +3 -0
  46. data/lib/puma/rack/urlmap.rb +9 -8
  47. data/lib/puma/reactor.rb +144 -0
  48. data/lib/puma/runner.rb +27 -1
  49. data/lib/puma/server.rb +135 -33
  50. data/lib/puma/single.rb +17 -3
  51. data/lib/puma/tcp_logger.rb +8 -1
  52. data/lib/puma/thread_pool.rb +70 -20
  53. data/lib/puma/util.rb +1 -5
  54. data/lib/rack/handler/puma.rb +58 -17
  55. data/tools/jungle/README.md +12 -2
  56. data/tools/jungle/init.d/README.md +9 -2
  57. data/tools/jungle/init.d/puma +85 -58
  58. data/tools/jungle/init.d/run-puma +16 -1
  59. data/tools/jungle/rc.d/README.md +74 -0
  60. data/tools/jungle/rc.d/puma +61 -0
  61. data/tools/jungle/rc.d/puma.conf +10 -0
  62. data/tools/jungle/upstart/puma.conf +1 -1
  63. data/tools/trickletest.rb +1 -1
  64. metadata +22 -94
  65. data/Gemfile +0 -13
  66. data/Manifest.txt +0 -78
  67. data/Rakefile +0 -158
  68. data/docs/config.md +0 -0
  69. data/lib/puma/rack/backports/uri/common_18.rb +0 -59
  70. data/lib/puma/rack/backports/uri/common_192.rb +0 -55
  71. data/puma.gemspec +0 -52
@@ -1,11 +1,22 @@
1
1
  require 'puma/runner'
2
+ require 'puma/detect'
3
+ require 'puma/plugin'
2
4
 
3
5
  module Puma
6
+ # This class is instantiated by the `Puma::Launcher` and used
7
+ # to boot and serve a Ruby application when no puma "workers" are needed
8
+ # i.e. only using "threaded" mode. For example `$ puma -t 1:5`
9
+ #
10
+ # At the core of this class is running an instance of `Puma::Server` which
11
+ # gets created via the `start_server` method from the `Puma::Runner` class
12
+ # that this inherits from.
4
13
  class Single < Runner
5
14
  def stats
6
- b = @server.backlog
7
- r = @server.running
8
- %Q!{ "backlog": #{b}, "running": #{r} }!
15
+ b = @server.backlog || 0
16
+ r = @server.running || 0
17
+ t = @server.pool_capacity || 0
18
+ m = @server.max_threads || 0
19
+ %Q!{ "backlog": #{b}, "running": #{r}, "pool_capacity": #{t}, "max_threads": #{m} }!
9
20
  end
10
21
 
11
22
  def restart
@@ -44,6 +55,7 @@ module Puma
44
55
  if JRubyRestart.daemon?
45
56
  # load and bind before redirecting IO so errors show up on stdout/stderr
46
57
  load_and_bind
58
+ redirect_io
47
59
  end
48
60
 
49
61
  already_daemon = JRubyRestart.daemon_init
@@ -84,6 +96,8 @@ module Puma
84
96
  load_and_bind
85
97
  end
86
98
 
99
+ Plugins.fire_background
100
+
87
101
  @launcher.write_state
88
102
 
89
103
  start_control
@@ -11,7 +11,14 @@ module Puma
11
11
  def log(who, str)
12
12
  now = Time.now.strftime("%d/%b/%Y %H:%M:%S")
13
13
 
14
- @logger.puts "#{now} - #{who} - #{str}"
14
+ log_str = "#{now} - #{who} - #{str}"
15
+
16
+ case @logger
17
+ when IO
18
+ @logger.puts log_str
19
+ when Events
20
+ @logger.log log_str
21
+ end
15
22
  end
16
23
 
17
24
  def call(env, socket)
@@ -1,13 +1,26 @@
1
1
  require 'thread'
2
2
 
3
3
  module Puma
4
- # A simple thread pool management object.
4
+ # Internal Docs for A simple thread pool management object.
5
5
  #
6
+ # Each Puma "worker" has a thread pool to process requests.
7
+ #
8
+ # First a connection to a client is made in `Puma::Server`. It is wrapped in a
9
+ # `Puma::Client` instance and then passed to the `Puma::Reactor` to ensure
10
+ # the whole request is buffered into memory. Once the request is ready, it is passed into
11
+ # a thread pool via the `Puma::ThreadPool#<<` operator where it is stored in a `@todo` array.
12
+ #
13
+ # Each thread in the pool has an internal loop where it pulls a request from the `@todo` array
14
+ # and proceses it.
6
15
  class ThreadPool
7
-
8
16
  class ForceShutdown < RuntimeError
9
17
  end
10
18
 
19
+ # How long, after raising the ForceShutdown of a thread during
20
+ # forced shutdown mode, to wait for the thread to try and finish
21
+ # up its work before leaving the thread to die on the vine.
22
+ SHUTDOWN_GRACE_TIME = 5 # seconds
23
+
11
24
  # Maintain a minimum of +min+ and maximum of +max+ threads
12
25
  # in the pool.
13
26
  #
@@ -45,11 +58,11 @@ module Puma
45
58
  @clean_thread_locals = false
46
59
  end
47
60
 
48
- attr_reader :spawned, :trim_requested
61
+ attr_reader :spawned, :trim_requested, :waiting
49
62
  attr_accessor :clean_thread_locals
50
63
 
51
64
  def self.clean_thread_locals
52
- Thread.current.keys.each do |key|
65
+ Thread.current.keys.each do |key| # rubocop: disable Performance/HashEachMethods
53
66
  Thread.current[key] = nil unless key == :__recursive_key__
54
67
  end
55
68
  end
@@ -60,6 +73,10 @@ module Puma
60
73
  @mutex.synchronize { @todo.size }
61
74
  end
62
75
 
76
+ def pool_capacity
77
+ waiting + (@max - spawned)
78
+ end
79
+
63
80
  # :nodoc:
64
81
  #
65
82
  # Must be called with @mutex held!
@@ -67,7 +84,9 @@ module Puma
67
84
  def spawn_thread
68
85
  @spawned += 1
69
86
 
70
- th = Thread.new do
87
+ th = Thread.new(@spawned) do |spawned|
88
+ # Thread name is new in Ruby 2.3
89
+ Thread.current.name = 'puma %03i' % spawned if Thread.current.respond_to?(:name=)
71
90
  todo = @todo
72
91
  block = @block
73
92
  mutex = @mutex
@@ -112,7 +131,8 @@ module Puma
112
131
 
113
132
  begin
114
133
  block.call(work, *extra)
115
- rescue Exception
134
+ rescue Exception => e
135
+ STDERR.puts "Error reached top of thread-pool: #{e.message} (#{e.class})"
116
136
  end
117
137
  end
118
138
 
@@ -146,9 +166,43 @@ module Puma
146
166
  end
147
167
  end
148
168
 
169
+ # This method is used by `Puma::Server` to let the server know when
170
+ # the thread pool can pull more requests from the socket and
171
+ # pass to the reactor.
172
+ #
173
+ # The general idea is that the thread pool can only work on a fixed
174
+ # number of requests at the same time. If it is already processing that
175
+ # number of requests then it is at capacity. If another Puma process has
176
+ # spare capacity, then the request can be left on the socket so the other
177
+ # worker can pick it up and process it.
178
+ #
179
+ # For example: if there are 5 threads, but only 4 working on
180
+ # requests, this method will not wait and the `Puma::Server`
181
+ # can pull a request right away.
182
+ #
183
+ # If there are 5 threads and all 5 of them are busy, then it will
184
+ # pause here, and wait until the `not_full` condition variable is
185
+ # signaled, usually this indicates that a request has been processed.
186
+ #
187
+ # It's important to note that even though the server might accept another
188
+ # request, it might not be added to the `@todo` array right away.
189
+ # For example if a slow client has only sent a header, but not a body
190
+ # then the `@todo` array would stay the same size as the reactor works
191
+ # to try to buffer the request. In tha scenario the next call to this
192
+ # method would not block and another request would be added into the reactor
193
+ # by the server. This would continue until a fully bufferend request
194
+ # makes it through the reactor and can then be processed by the thread pool.
149
195
  def wait_until_not_full
150
196
  @mutex.synchronize do
151
- until @todo.size - @waiting < @max - @spawned or @shutdown
197
+ while true
198
+ return if @shutdown
199
+
200
+ # If we can still spin up new threads and there
201
+ # is work queued that cannot be handled by waiting
202
+ # threads, then accept more work until we would
203
+ # spin up the max number of threads.
204
+ return if @todo.size - @waiting < @max - @spawned
205
+
152
206
  @not_full.wait @mutex
153
207
  end
154
208
  end
@@ -178,7 +232,9 @@ module Puma
178
232
  @spawned -= 1
179
233
  end
180
234
 
181
- @workers -= dead_workers
235
+ @workers.delete_if do |w|
236
+ dead_workers.include?(w)
237
+ end
182
238
  end
183
239
  end
184
240
 
@@ -206,7 +262,7 @@ module Puma
206
262
  end
207
263
  end
208
264
 
209
- def auto_trim!(timeout=5)
265
+ def auto_trim!(timeout=30)
210
266
  @auto_trim = AutoTrim.new(self, timeout)
211
267
  @auto_trim.start!
212
268
  end
@@ -254,18 +310,12 @@ module Puma
254
310
  @workers.dup
255
311
  end
256
312
 
257
- case timeout
258
- when -1
313
+ if timeout == -1
314
+ # Wait for threads to finish without force shutdown.
259
315
  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
316
  else
317
+ # Wait for threads to finish after n attempts (+timeout+).
318
+ # If threads are still running, it will forcefully kill them.
269
319
  timeout.times do
270
320
  threads.delete_if do |t|
271
321
  t.join 1
@@ -283,7 +333,7 @@ module Puma
283
333
  end
284
334
 
285
335
  threads.each do |t|
286
- t.join Const::SHUTDOWN_GRACE_TIME
336
+ t.join SHUTDOWN_GRACE_TIME
287
337
  end
288
338
  end
289
339
 
@@ -1,10 +1,6 @@
1
1
  major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
2
2
 
3
- if major == 1 && minor < 9
4
- require 'puma/rack/backports/uri/common_18'
5
- elsif major == 1 && minor == 9 && patch == 2 && RUBY_PATCHLEVEL <= 328 && RUBY_ENGINE != 'jruby'
6
- require 'puma/rack/backports/uri/common_192'
7
- elsif major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
3
+ if major == 1 && minor == 9 && patch == 3 && RUBY_PATCHLEVEL < 125
8
4
  require 'puma/rack/backports/uri/common_193'
9
5
  else
10
6
  require 'uri/common'
@@ -1,5 +1,4 @@
1
1
  require 'rack/handler'
2
- require 'puma'
3
2
 
4
3
  module Rack
5
4
  module Handler
@@ -9,38 +8,58 @@ module Rack
9
8
  :Silent => false
10
9
  }
11
10
 
12
- def self.run(app, options = {})
13
- options = DEFAULT_OPTIONS.merge(options)
11
+ def self.config(app, options = {})
12
+ require 'puma'
13
+ require 'puma/configuration'
14
+ require 'puma/events'
15
+ require 'puma/launcher'
16
+
17
+ default_options = DEFAULT_OPTIONS.dup
18
+
19
+ # Libraries pass in values such as :Port and there is no way to determine
20
+ # if it is a default provided by the library or a special value provided
21
+ # by the user. A special key `user_supplied_options` can be passed. This
22
+ # contains an array of all explicitly defined user options. We then
23
+ # know that all other values are defaults
24
+ if user_supplied_options = options.delete(:user_supplied_options)
25
+ (options.keys - user_supplied_options).each do |k|
26
+ default_options[k] = options.delete(k)
27
+ end
28
+ end
14
29
 
15
- conf = ::Puma::Configuration.new(options) do |c|
16
- c.quiet
30
+ conf = ::Puma::Configuration.new(options, default_options) do |user_config, file_config, default_config|
31
+ user_config.quiet
17
32
 
18
33
  if options.delete(:Verbose)
19
34
  app = Rack::CommonLogger.new(app, STDOUT)
20
35
  end
21
36
 
22
37
  if options[:environment]
23
- c.environment options[:environment]
38
+ user_config.environment options[:environment]
24
39
  end
25
40
 
26
41
  if options[:Threads]
27
42
  min, max = options.delete(:Threads).split(':', 2)
28
- c.threads min, max
43
+ user_config.threads min, max
29
44
  end
30
45
 
31
- host = options[:Host]
32
-
33
- if host && (host[0,1] == '.' || host[0,1] == '/')
34
- c.bind "unix://#{host}"
35
- else
36
- host ||= ::Puma::Configuration::DefaultTCPHost
37
- port = options[:Port] || ::Puma::Configuration::DefaultTCPPort
38
-
39
- c.port port, host
46
+ if options[:Host] || options[:Port]
47
+ host = options[:Host] || default_options[:Host]
48
+ port = options[:Port] || default_options[:Port]
49
+ self.set_host_port_to_config(host, port, user_config)
40
50
  end
41
51
 
42
- c.app app
52
+ self.set_host_port_to_config(default_options[:Host], default_options[:Port], default_config)
53
+
54
+ user_config.app app
43
55
  end
56
+ conf
57
+ end
58
+
59
+
60
+
61
+ def self.run(app, options = {})
62
+ conf = self.config(app, options)
44
63
 
45
64
  events = options.delete(:Silent) ? ::Puma::Events.strings : ::Puma::Events.stdio
46
65
 
@@ -64,6 +83,28 @@ module Rack
64
83
  "Verbose" => "Don't report each request (default: false)"
65
84
  }
66
85
  end
86
+ private
87
+ def self.set_host_port_to_config(host, port, config)
88
+ config.clear_binds! if host || port
89
+
90
+ if host && (host[0,1] == '.' || host[0,1] == '/')
91
+ config.bind "unix://#{host}"
92
+ elsif host && host =~ /^ssl:\/\//
93
+ uri = URI.parse(host)
94
+ uri.port ||= port || ::Puma::Configuration::DefaultTCPPort
95
+ config.bind uri.to_s
96
+ else
97
+
98
+ if host
99
+ port ||= ::Puma::Configuration::DefaultTCPPort
100
+ end
101
+
102
+ if port
103
+ host ||= ::Puma::Configuration::DefaultTCPHost
104
+ config.port port, host
105
+ end
106
+ end
107
+ end
67
108
  end
68
109
 
69
110
  register :puma, Puma
@@ -1,9 +1,19 @@
1
1
  # Puma as a service
2
2
 
3
+ ## Upstart
4
+
5
+ See `/tools/jungle/upstart` for Ubuntu's upstart scripts.
6
+
7
+ ## Systemd
8
+
9
+ See [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md).
10
+
3
11
  ## Init.d
4
12
 
13
+ Deprecatation Warning : `init.d` was replaced by `systemd` since Debian 8 and Ubuntu 16.04, you should look into [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md) unless you are on an older OS.
14
+
5
15
  See `/tools/jungle/init.d` for tools to use with init.d and start-stop-daemon.
6
16
 
7
- ## Upstart
17
+ ## rc.d
8
18
 
9
- See `/tools/jungle/upstart` for Ubuntu's upstart scripts.
19
+ See `/tools/jungle/rc.d` for FreeBSD's rc.d scripts
@@ -1,5 +1,7 @@
1
1
  # Puma daemon service
2
2
 
3
+ Deprecatation Warning : `init.d` was replaced by `systemd` since Debian 8 and Ubuntu 16.04, you should look into [/docs/systemd](https://github.com/puma/puma/blob/master/docs/systemd.md) unless you are on an older OS.
4
+
3
5
  Init script to manage multiple Puma servers on the same box using start-stop-daemon.
4
6
 
5
7
  ## Installation
@@ -22,16 +24,21 @@ Init script to manage multiple Puma servers on the same box using start-stop-dae
22
24
 
23
25
  Puma apps are held in /etc/puma.conf by default. It's mainly a CSV file and every line represents one app. Here's the syntax:
24
26
 
25
- app-path,user,config-file-path,log-file-path
27
+ app-path,user,config-file-path,log-file-path,environment-variables
26
28
 
27
29
  You can add an instance by editing the file or running the following command:
28
30
 
29
31
  sudo /etc/init.d/puma add /path/to/app user /path/to/app/config/puma.rb /path/to/app/log/puma.log
30
32
 
31
- The config and log paths are optional parameters and default to:
33
+ The config and log paths, as well as the environment variables, are optional parameters and default to:
32
34
 
33
35
  * config: /path/to/app/*config/puma.rb*
34
36
  * log: /path/to/app/*log/puma.log*
37
+ * environment: (empty)
38
+
39
+ Multiple environment variables need to be separated by a semicolon, e.g.
40
+
41
+ FOO=1;BAR=2
35
42
 
36
43
  To remove an app, simply delete the line from the config file or run:
37
44
 
@@ -5,9 +5,9 @@
5
5
  # Required-Stop: $remote_fs $syslog
6
6
  # Default-Start: 2 3 4 5
7
7
  # Default-Stop: 0 1 6
8
- # Short-Description: Example initscript
9
- # Description: This file should be used to construct scripts to be
10
- # placed in /etc/init.d.
8
+ # Short-Description: Puma web server
9
+ # Description: A ruby web server built for concurrency http://puma.io
10
+ # initscript to be placed in /etc/init.d.
11
11
  ### END INIT INFO
12
12
 
13
13
  # Author: Darío Javier Cravero <dario@exordo.com>
@@ -39,17 +39,7 @@ do_start() {
39
39
  log_daemon_msg "=> Running the jungle..."
40
40
  for i in $JUNGLE; do
41
41
  dir=`echo $i | cut -d , -f 1`
42
- user=`echo $i | cut -d , -f 2`
43
- config_file=`echo $i | cut -d , -f 3`
44
- if [ "$config_file" = "" ]; then
45
- config_file="$dir/config/puma.rb"
46
- fi
47
- log_file=`echo $i | cut -d , -f 4`
48
- if [ "$log_file" = "" ]; then
49
- log_file="$dir/log/puma.log"
50
- fi
51
- environment=`echo $i | cut -d , -f 5`
52
- do_start_one $dir $user $config_file $log_file $environment
42
+ do_start_one $dir
53
43
  done
54
44
  }
55
45
 
@@ -58,29 +48,42 @@ do_start_one() {
58
48
  if [ -e $PIDFILE ]; then
59
49
  PID=`cat $PIDFILE`
60
50
  # If the puma isn't running, run it, otherwise restart it.
61
- if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
62
- do_start_one_do $1 $2 $3 $4 $5
51
+ if ps -p $PID > /dev/null; then
52
+ do_start_one_do $1
63
53
  else
64
54
  do_restart_one $1
65
55
  fi
66
56
  else
67
- do_start_one_do $1 $2 $3 $4 $5
57
+ do_start_one_do $1
68
58
  fi
69
59
  }
70
60
 
71
61
  do_start_one_do() {
72
- log_daemon_msg "--> Woke up puma $1"
73
- log_daemon_msg "user $2"
74
- log_daemon_msg "log to $4"
62
+ i=`grep $1 $CONFIG`
63
+ dir=`echo $i | cut -d , -f 1`
64
+ user=`echo $i | cut -d , -f 2`
65
+ config_file=`echo $i | cut -d , -f 3`
66
+ if [ "$config_file" = "" ]; then
67
+ config_file="$dir/config/puma.rb"
68
+ fi
69
+ log_file=`echo $i | cut -d , -f 4`
70
+ if [ "$log_file" = "" ]; then
71
+ log_file="$dir/log/puma.log"
72
+ fi
73
+ environment=`echo $i | cut -d , -f 5`
74
+
75
+ log_daemon_msg "--> Woke up puma $dir"
76
+ log_daemon_msg "user $user"
77
+ log_daemon_msg "log to $log_file"
75
78
 
76
- if [ ! -z "$5" ]; then
77
- for e in $(echo "$5" | tr ';' '\n'); do
79
+ if [ ! -z "$environment" ]; then
80
+ for e in $(echo "$environment" | tr ';' '\n'); do
78
81
  log_daemon_msg "environment $e"
79
82
  v=${e%%\=*} ; eval "$e" ; export $v
80
83
  done
81
84
  fi
82
85
 
83
- start-stop-daemon --verbose --start --chdir $1 --chuid $2 --background --exec $RUNPUMA -- $1 $3 $4
86
+ start-stop-daemon --verbose --start --chdir $dir --chuid $user --background --exec $RUNPUMA -- $dir $config_file $log_file
84
87
  }
85
88
 
86
89
  #
@@ -102,7 +105,7 @@ do_stop_one() {
102
105
  STATEFILE=$1/tmp/puma/state
103
106
  if [ -e $PIDFILE ]; then
104
107
  PID=`cat $PIDFILE`
105
- if [ "`ps -A -o pid= | grep -c $PID`" -eq 0 ]; then
108
+ if ps -p $PID > /dev/null; then
106
109
  log_daemon_msg "---> Puma $1 isn't running."
107
110
  else
108
111
  log_daemon_msg "---> About to kill PID `cat $PIDFILE`"
@@ -135,31 +138,41 @@ do_restart() {
135
138
  #
136
139
  do_restart_one() {
137
140
  PIDFILE=$1/tmp/puma/pid
138
- i=`grep $1 $CONFIG`
139
- dir=`echo $i | cut -d , -f 1`
140
-
141
+
141
142
  if [ -e $PIDFILE ]; then
142
143
  log_daemon_msg "--> About to restart puma $1"
143
- if [ "$USE_LOCAL_BUNDLE" -eq 1 ]; then
144
- cd $1 && bundle exec pumactl --state $dir/tmp/puma/state restart
145
- else
146
- pumactl --state $dir/tmp/puma/state restart
147
- fi
148
- # kill -s USR2 `cat $PIDFILE`
144
+ kill -s USR2 `cat $PIDFILE`
149
145
  # TODO Check if process exist
150
146
  else
151
- log_daemon_msg "--> Your puma was never playing... Let's get it out there first"
152
- user=`echo $i | cut -d , -f 2`
153
- config_file=`echo $i | cut -d , -f 3`
154
- if [ "$config_file" = "" ]; then
155
- config_file="$dir/config/puma.rb"
156
- fi
157
- log_file=`echo $i | cut -d , -f 4`
158
- if [ "$log_file" = "" ]; then
159
- log_file="$dir/log/puma.log"
160
- fi
161
- environment=`echo $i | cut -d , -f 5`
162
- do_start_one $dir $user $config_file $log_file $environment
147
+ log_daemon_msg "--> Your puma was never playing... Let's get it out there first"
148
+ do_start_one $1
149
+ fi
150
+ return 0
151
+ }
152
+
153
+ #
154
+ # Function that phased restarts the jungle
155
+ #
156
+ do_phased_restart() {
157
+ for i in $JUNGLE; do
158
+ dir=`echo $i | cut -d , -f 1`
159
+ do_phased_restart_one $dir
160
+ done
161
+ }
162
+
163
+ #
164
+ # Function that sends a SIGUSR1 to the daemon/service
165
+ #
166
+ do_phased_restart_one() {
167
+ PIDFILE=$1/tmp/puma/pid
168
+
169
+ if [ -e $PIDFILE ]; then
170
+ log_daemon_msg "--> About to restart puma $1"
171
+ kill -s USR1 `cat $PIDFILE`
172
+ # TODO Check if process exist
173
+ else
174
+ log_daemon_msg "--> Your puma was never playing... Let's get it out there first"
175
+ do_start_one $1
163
176
  fi
164
177
  return 0
165
178
  }
@@ -256,16 +269,25 @@ do_remove() {
256
269
 
257
270
  config_bundler() {
258
271
  HOME="$(eval echo ~$(id -un))"
259
- if [ -d "/usr/local/rbenv/bin" ]; then
272
+
273
+ if [ -d "$1/.rbenv/bin" ]; then
274
+ PATH="$1/.rbenv/bin:$1/.rbenv/shims:$1"
275
+ eval "$(rbenv init -)"
276
+ USE_LOCAL_BUNDLE=1
277
+ return 0
278
+
279
+ elif [ -d "/usr/local/rbenv/bin" ]; then
260
280
  PATH="/usr/local/rbenv/bin:/usr/local/rbenv/shims:$PATH"
261
281
  eval "$(rbenv init -)"
262
282
  USE_LOCAL_BUNDLE=1
263
283
  return 0
284
+
264
285
  elif [ -d "$HOME/.rbenv/bin" ]; then
265
286
  PATH="$HOME/.rbenv/bin:$HOME/.rbenv/shims:$PATH"
266
287
  eval "$(rbenv init -)"
267
288
  USE_LOCAL_BUNDLE=1
268
289
  return 0
290
+
269
291
  # TODO: test rvm
270
292
  # elif [ -f /etc/profile.d/rvm.sh ]; then
271
293
  # source /etc/profile.d/rvm.sh
@@ -296,16 +318,7 @@ case "$1" in
296
318
  else
297
319
  i=`grep $2 $CONFIG`
298
320
  dir=`echo $i | cut -d , -f 1`
299
- user=`echo $i | cut -d , -f 2`
300
- config_file=`echo $i | cut -d , -f 3`
301
- if [ "$config_file" = "" ]; then
302
- config_file="$dir/config/puma.rb"
303
- fi
304
- log_file=`echo $i | cut -d , -f 4`
305
- if [ "$log_file" = "" ]; then
306
- log_file="$dir/log/puma.log"
307
- fi
308
- do_start_one $dir $user $config_file $log_file
321
+ do_start_one $dir
309
322
  fi
310
323
  case "$?" in
311
324
  0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
@@ -355,6 +368,20 @@ case "$1" in
355
368
  2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
356
369
  esac
357
370
  ;;
371
+ phased-restart)
372
+ log_daemon_msg "Restarting (phased) $DESC" "$NAME"
373
+ if [ "$#" -eq 1 ]; then
374
+ do_phased_restart
375
+ else
376
+ i=`grep $2 $CONFIG`
377
+ dir=`echo $i | cut -d , -f 1`
378
+ do_phased_restart_one $dir
379
+ fi
380
+ case "$?" in
381
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
382
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
383
+ esac
384
+ ;;
358
385
  add)
359
386
  if [ "$#" -lt 3 ]; then
360
387
  echo "Please, specify the app's directory and the user that will run it at least."
@@ -383,11 +410,11 @@ case "$1" in
383
410
  ;;
384
411
  *)
385
412
  echo "Usage:" >&2
386
- echo " Run the jungle: $SCRIPTNAME {start|stop|status|restart}" >&2
413
+ echo " Run the jungle: $SCRIPTNAME {start|stop|status|restart|phased-restart}" >&2
387
414
  echo " Add a Puma: $SCRIPTNAME add /path/to/app user /path/to/app/config/puma.rb /path/to/app/config/log/puma.log"
388
415
  echo " config and log are optionals."
389
416
  echo " Remove a Puma: $SCRIPTNAME remove /path/to/app"
390
- echo " On a Puma: $SCRIPTNAME {start|stop|status|restart} PUMA-NAME" >&2
417
+ echo " On a Puma: $SCRIPTNAME {start|stop|status|restart|phased-restart} PUMA-NAME" >&2
391
418
  exit 3
392
419
  ;;
393
420
  esac